Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.03.21;
Скачать: CL | DM;

Вниз

canvas.textWidth для разных стилей   Найти похожие ветки 

 
novichek   (2010-01-18 22:31) [0]

Устанавливаю стиль в fsItalic.
canvas.textWidth возвращает то же самое что и при отсутствии стиля.
В результате конец текста обрезан немного.

Подскажите пожалуйста, с чем связано, что для одного шрифта результат вроде бы правильный, для другого нет..

в процессе мучения, из-за выхода текста за размеры, набросал для теста:

procedure TForm1.Button1Click(Sender: TObject);
const
//  test = "Проверка связи ры ры ры рычаг";
 test = "test test test test";
var
 bmp: TBitmap;
 x1, x2, x3, x4: Integer;

 procedure drawbmp(offset: Integer);
 begin
    bmp.Canvas.FillRect(bmp.Canvas.ClipRect);
    bmp.Canvas.TextOut(0, 0, test);
    form1.Canvas.Draw(0, offset, bmp);
 end;

begin

 bmp:= TBitmap.Create;
 bmp.Canvas.Brush.Color:= clBlack;
 bmp.Canvas.Font.Color:= clWhite;

 bmp.Canvas.Font.Name:= "Comic Sans MS";
 bmp.Canvas.Font.Size:= 40;
 bmp.Height:= bmp.Canvas.TextHeight("Py");

 bmp.Canvas.Font.Style:=[];
 x1:= bmp.Canvas.TextWidth(test);
 bmp.Width:= x1;
 drawbmp(0);

 bmp.Canvas.Font.Style:=[fsItalic];
 x2:= bmp.Canvas.TextWidth(test);
 bmp.Width:= x2;
 drawbmp(bmp.Height + 10);

 bmp.Canvas.Font.Style:=[fsBold];
 x3:= bmp.Canvas.TextWidth(test);
 bmp.Width:= x3;
 drawbmp(bmp.Height*2 + 10*2);

 bmp.Canvas.Font.Style:=[fsBold, fsItalic];
 x4:= bmp.Canvas.TextWidth(test);
 bmp.Width:= x4;
 drawbmp(bmp.Height*3 + 10*3);

 bmp.Free;

 ShowMessage("[] - "+IntToStr(x1)+",  [fsItalic] - "+IntToStr(x2)+",  [fsBold] - "+IntToStr(x3)+",  [fsBold, fsItalic] - "+IntToStr(x4));

end;

с чего и сделал вывод, что возвращаемые значения ширины немного не понятные..

как узнать  для данного шрифта правильный размер при fsItalic ?


 
Игорь Шевченко ©   (2010-01-18 22:42) [1]


> canvas.textWidth возвращает то же самое что и при отсутствии
> стиля.


Было бы странно обратное.

http://www.rsdn.ru/forum/winapi/1098456.flat.aspx


 
novichek   (2010-01-18 22:51) [2]

ну было бы..
только вот для одного шрифта разное для другого одинаковое а то ещё и меньше..

простите, я немного не силен в Си, не могли бы показать на дельфи как правильно узнать реальную ширину строки с учётом fsItalic ?


 
antonn ©   (2010-01-18 23:13) [3]

когда то создавал подобную тему, ответ 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;

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;


мой велосипедный ужас:
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;


 
Игорь Шевченко ©   (2010-01-18 23:13) [4]

http://support.microsoft.com/kb/74298/en-us

Сильным в C быть не надо, в статье перечислены функции, котоые нужно вызывать в нужной последовательности.

Ширина строки определяется абсолютно верно, а для того, чтобы определить ширину прямоугольника, описанного вокруг строки, нужно отнимать, как написано в статье, Textmetric.tmOverhang

Есть более сложный и более точный способ:

http://www.codeproject.com/KB/GDI/italicText.aspx


 
novichek   (2010-01-18 23:19) [5]

хотел посмотреть в самой дельфи, как например авторазмер вычисляется для той же лабельки, так и нифига некорректно.

установил размер в 40, жирный-нклонный и шрифт Comic Sans MS, при установке AutoSize край текста не входит..

попробывал GetTextExtentPoint32(bmp.Canvas.Handle, PChar(text), Length(text), sz);

sz.cy то же неверно...

помогите кто знает как правильно узнать ширину..


 
Игорь Шевченко ©   (2010-01-18 23:20) [6]


> GetTextExtentPoint32(bmp.Canvas.Handle, PChar(text), Length(text),
>  sz);


Это то же самое, что TextWidth


 
novichek   (2010-01-18 23:20) [7]

спасибо, пока писал Вы ответили..
попробую разобраться ещё раз )


 
antonn ©   (2010-01-18 23:22) [8]

если искать ширину попиксельно с включенным clearType то габариты текста будут сильно завышены :(


 
Игорь Шевченко ©   (2010-01-18 23:23) [9]

А на практике для Italic увеличивают ширину на значение высоты шрифта, для 98% случаев подходит.


 
Anatoly Podgoretsky ©   (2010-01-18 23:27) [10]

> Игорь Шевченко  (18.01.2010 23:23:09)  [9]

А почему не на sin(a), угол же наклона порядка 15 градусов, а не 90


 
antonn ©   (2010-01-18 23:32) [11]

есть шрифты типа "Пушкин-style" у которых в italic вензеля и рюшечки так забабахиваются в сторону... :(


 
Игорь Шевченко ©   (2010-01-18 23:44) [12]

Anatoly Podgoretsky ©   (18.01.10 23:27) [10]

А фиг знает


 
Anatoly Podgoretsky ©   (2010-01-18 23:53) [13]

> antonn  (18.01.2010 23:32:11)  [11]

Ну и что, они учитываются в метрики и + 15%
Шрифты то пропорциональные.


 
Anatoly Podgoretsky ©   (2010-01-18 23:53) [14]

> Игорь Шевченко  (18.01.2010 23:44:12)  [12]

Перестраховка?


 
novichek   (2010-01-19 00:11) [15]

блин, кипит моск...
зжальтесь, покажите на дельфи как использовать GetCharWidth32, GetCharWidth..

вообще зациклился, так как у меня строка в юникоде и могут быть и китайские символы..


 
Игорь Шевченко ©   (2010-01-19 00:15) [16]

Anatoly Podgoretsky ©   (18.01.10 23:53) [14]

Отчасти, я думаю, вместо дополнительных вызовов GetABCCharWidths


 
Игорь Шевченко ©   (2010-01-19 00:16) [17]


>  и могут быть и китайские символы..


Китайские это фигня по сравнению с арабскими


 
novichek   (2010-01-19 00:23) [18]

что такое GetABCCharWidths ?
я так понимаю, мне нужно узнать ширину последнего символа и учитывать разницу в наклоне..

arr: array[0..0] of TABC;
...

GetCharABCWidthsFloat(bmp.Canvas.Handle, Ord("t"), Ord("t"), arr);

arr[0].abcC отрицательно, да и другие вообще огромные числа..

что дальге делать не пойму, в сишном коде

if(dOverhangTrailing<0)
  {
   lWidth-=(LONG)dOverhangTrailing; // Last character"s overhang
                 }

что значит ?


 
Игорь Шевченко ©   (2010-01-19 00:27) [19]


> что такое GetABCCharWidths


http://msdn.microsoft.com/en-us/library/dd144857(VS.85).aspx


 
novichek   (2010-01-19 00:46) [20]

GetCharABCWidthsW(bmp.Canvas.Handle, 0, 255, arr);
dOverhangTrailing:= 0;
for I := 1 to length(test) do dOverhangTrailing:= dOverhangTrailing + arr[Ord(test[i])].abcA+ arr[Ord(test[i])].abcB+ arr[Ord(test[i])].abcC;

bmp.Width:= dOverhangTrailing;

почему-то то же самое что и TextWidth - край текста вышел за пределы..


 
novichek   (2010-01-19 00:50) [21]

"А на практике для Italic увеличивают ширину на значение высоты шрифта, для 98% случаев подходит."

dOverhangTrailing:= bmp.Canvas.TextWidth(test) + bmp.Canvas.TextHeight("t");

bmp.Width:= dOverhangTrailing;

слишком уж много...


 
novichek   (2010-01-19 01:10) [22]

попробывал явно задать чуть побольше ширину и отрисовать текст

   bmp.Canvas.TextOut(0, 0, test);

затем думал установить реальную ширину, используя крайнюю позицию

   bmp.Width:= bmp.Canvas.PenPos.X;

нифига.. всё равно не учитывается Italic..

я так понял никто тут не поможет?


 
novichek   (2010-01-19 01:23) [23]

GetCharABCWidthsW(bmp.Canvas.Handle, ord(test[length(test)]), ord(test[length(test)]), arr);
dOverhangTrailing:= bmp.Canvas.TextWidth(test);

if arr[0].abcC < 0 then dOverhangTrailing:= dOverhangTrailing + (arr[0].abcC*-1);

bmp.Width:= dOverhangTrailing;


 
Игорь Шевченко ©   (2010-01-19 01:39) [24]

novichek   (19.01.10 01:23) [23]

Попробуй, чтобы влезло слово fluff или Fluff


 
novichek   (2010-01-19 01:49) [25]

нормально вроде бы входит..

 function GetWidthText(bmp: TBitmap; text: String): Integer;
 var
   arr: array[0..0] of TABC;
 begin
   if trim(text)="" then exit(0);
   result:= bmp.Canvas.TextWidth(text);
   GetCharABCWidthsW(bmp.Canvas.Handle, ord(text[system.Length(text)]), ord(text[system.Length(text)]), arr);
   if arr[0].abcC < 0 then result:= result - arr[0].abcC;
 end;


 
Демо ©   (2010-01-19 09:54) [26]


> novichek   (19.01.10 01:49) [25]


А ты не пробовал просто DrawText использовать с флагом DT_CALCRECT?


 
antonn ©   (2010-01-19 12:46) [27]


> А ты не пробовал просто DrawText использовать с флагом DT_CALCRECT?

с ним такая же ерунда


 
Anatoly Podgoretsky ©   (2010-01-19 13:11) [28]

> antonn  (19.01.2010 12:46:27)  [27]

Не ищи не ерунды, это ошибка (особенность) в генофонде. Борются добавляя предопределенное смещение


 
antonn ©   (2010-01-19 13:53) [29]

я бы догадался, что борются с этим добавляя некое смещение. Только имея дело не только с tahoma, а с более размашистыми шрифтами предопределенное смещение нужно вычислять самому, либо просто узнавать размеры отрендеренного шрифта.


 
Игорь Шевченко ©   (2010-01-19 15:43) [30]

antonn ©   (19.01.10 13:53) [29]

Я вчера малость попробовал, так чтобы слово fluff влезло, надо высоту шрифта прибавлять. Шрифт брал размером 72, с засечками и без них.


 
antonn ©   (2010-01-19 15:53) [31]

все таки это смахивает больше на костыль :)


 
Игорь Шевченко ©   (2010-01-19 15:55) [32]

antonn ©   (19.01.10 15:53) [31]


> все таки это смахивает больше на костыль


Разумеется. Для некостыльных решений я привел три ссылки, еще у Фэня в книжке подробно обсуждается эта проблема.


 
Демо ©   (2010-01-19 17:36) [33]

В своё время была у меня такая задача.
Я поступил таким образом:

Для каждого стиля завёл массив
   WSym: array[Char] of Integer;
   HSym: array[Char] of Integer;
   WSymBold: array[Char] of Integer;
   HSymBold: array[Char] of Integer;
   WSymItalic: array[Char] of Integer;
   HSymItalic: array[Char] of Integer;
   WSymUnderLine: array[Char] of Integer;
   HSymUnderLine: array[Char] of Integer;


Предварительно вычислял размеры символов и заносил в массив.
При выводе на холст оставалось пройти по строке, получить длину каждого символа и рассчитать длину строки.


 
Игорь Шевченко ©   (2010-01-19 17:45) [34]

Демо ©   (19.01.10 17:36) [33]

А ничего, что размер символа зависит от его позиции ?


 
Демо ©   (2010-01-19 19:32) [35]


> А ничего, что размер символа зависит от его позиции ?


Поясни мысль?


 
Игорь Шевченко ©   (2010-01-19 19:45) [36]

Демо ©   (19.01.10 19:32) [35]

Одни и те же символы по соседству с разными символами могут быть придвинуты к соседнему или наоборот, отодвинуты от соседа. То есть, для получения размера строки важна не сумма ширин отдельных символов, а сумма с учетом их взаимного расположения.


 
Демо ©   (2010-01-19 20:22) [37]


> Игорь Шевченко ©   (19.01.10 19:45) [36]
> Демо ©   (19.01.10 19:32) [35] Одни и те же символы по соседству
> с разными символами могут быть придвинуты к соседнему или
> наоборот, отодвинуты от соседа. То есть, для получения размера
> строки важна не сумма ширин отдельных символов, а сумма
> с учетом их взаимного расположения.


Понятно.
У меня вывод был посимвольный, поэтомусмещение вычислялось относительно предыдущего символа.
Вроде как всё было нормально. Ничто никуда не съезжало.


 
Игорь Шевченко ©   (2010-01-19 20:45) [38]

Для расчета позиций символов с учетом их взаимного расположения нужно вызывать функции GetKerningPairs и(или) GetCharacterPlacement

Все это я к чему - вывод текста может оказаться весьма нетривиальным занятием


 
Anatoly Podgoretsky ©   (2010-01-19 21:16) [39]

> Демо  (19.01.2010 17:36:33)  [33]

А нафига ты посимвольно их делаешь, когда у тебя есть размер всей строки, вот его и корректируй


 
Anatoly Podgoretsky ©   (2010-01-19 21:17) [40]

> Игорь Шевченко  (19.01.2010 20:45:38)  [38]

Вот поэтому и системой и делается простой расчет, нафига им нетривиальность.



Страницы: 1 2 вся ветка

Текущий архив: 2010.03.21;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.14 c
1-1240562868
Unknown user
2009-04-24 12:47
2010.03.21
Странная утечка памяти, обнаруживаемая EurekaLog


15-1262453629
Оно-16
2010-01-02 20:33
2010.03.21
Удаленный помощник удали троян


15-1262175997
Ega23
2009-12-30 15:26
2010.03.21
С наступающим, товарищи!


1-1243255012
TStas
2009-05-25 16:36
2010.03.21
Как удалить файл в корзину?


11-1214300690
Valera
2008-06-24 13:44
2010.03.21
Замена системных модулей для Delphi7.