Вопрос по измерению фонтов
От: Andrej-V  
Дата: 09.05.08 17:48
Оценка:
Подскажите пожалуйста на вопрос в коде
//g -объект Graphics
                g.PageUnit = GraphicsUnit.Pixel;
                float scale = g.PageScale;//1.0
                float xdpi = g.DpiX;//96.0 - количество пикселей на логический дюйм по горизонтали
                float ydpi = g.DpiY;//96.0 - количество пикселей на логический дюйм по вертикали
                Font f = new Font("Arial", 10);//10 - высота шрифта в пунктах (1/72 логического дюйма); 10*(1/72)*96 =13.3333.... --высота шрифта в пикселях                
                float MeasureStringHeight = (g.MeasureString("a", f)).Height;//16.5624981 это число не зависит от буквы (строчная или прописная), которая измеряется и потому это, вероятно, высота шрифта включающая межстрочное пространство в пикселях, т.е. межстрочное пространство с учетом предыдущей строки = 16.5624981-13.3333333=3.2291648 пикселям      
                int fHeight = f.Height;//16 - это скорее всего округление числа предыдущей строки            
                int LineSpacing = f.FontFamily.GetLineSpacing(FontStyle.Regular);//2355 Единицы измерения? В пунктах (как написано у Троелсена )? Тогда в логических дюймах получается 2355/72=32.708333..., а в пикселях 32.708333*96=3140 - это не 3.2291648 пикселя из предыдущей стоки. Даже если единицы - тысячные доли пункта (это бы соответствовало порядку чисел)все равно расхождение (совпадение только в старшем знаке)??? 
                
                int CellAscent = f.FontFamily.GetCellAscent(FontStyle.Regular);//1854
                int CellDescent = f.FontFamily.GetCellDescent(FontStyle.Regular);//434
Re: Вопрос по измерению фонтов
От: vmpire Россия  
Дата: 12.05.08 20:33
Оценка:
Здравствуйте, Andrej-V, Вы писали:

AV>Подскажите пожалуйста на вопрос в коде

AV>
AV>                int LineSpacing = f.FontFamily.GetLineSpacing(FontStyle.Regular);//2355 Единицы измерения? В пунктах (как написано у Троелсена )? Тогда в логических дюймах получается 2355/72=32.708333..., а в пикселях 32.708333*96=3140 - это не 3.2291648 пикселя из предыдущей стоки. Даже если единицы - тысячные доли пункта (это бы соответствовало порядку чисел)все равно расхождение (совпадение только в старшем знаке)??? 
                
AV>


Если открыть MSDN на описании метода GetLineSpacing (http://msdn.microsoft.com/en-us/library/system.drawing.fontfamily.getlinespacing.aspx)
и пойти по ссылке How to: Obtain Font Metrics (http://msdn.microsoft.com/en-us/library/system.drawing.fontfamily.getlinespacing.aspx),
то Вы легко получите ответ на свой вопрос. И передадите Троелсену.
Re[2]: Вопрос по измерению фонтов
От: Andrej-V  
Дата: 12.05.08 21:36
Оценка:
Здравствуйте, vmpire, Вы писали:

V>Если открыть MSDN на описании метода GetLineSpacing (http://msdn.microsoft.com/en-us/library/system.drawing.fontfamily.getlinespacing.aspx)

V>и пойти по ссылке How to: Obtain Font Metrics (http://msdn.microsoft.com/en-us/library/system.drawing.fontfamily.getlinespacing.aspx),
V>то Вы легко получите ответ на свой вопрос. И передадите Троелсену.

Спасибо, я это видел до написания вопроса и не понял, что такое design units. Это не пиксели, и не тысячи пикселей, не пункты и не тысячи пунктов и не логические дюймы (с точностью до 10^n) т.к. получается расхождение, описанное в первом сообщении.
Re[3]: Вопрос по измерению фонтов
От: vmpire Россия  
Дата: 13.05.08 09:40
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:

AV>Здравствуйте, vmpire, Вы писали:


V>>Если открыть MSDN на описании метода GetLineSpacing (http://msdn.microsoft.com/en-us/library/system.drawing.fontfamily.getlinespacing.aspx)

V>>и пойти по ссылке How to: Obtain Font Metrics (http://msdn.microsoft.com/en-us/library/system.drawing.fontfamily.getlinespacing.aspx),
V>>то Вы легко получите ответ на свой вопрос. И передадите Троелсену.

AV>Спасибо, я это видел до написания вопроса и не понял, что такое design units. Это не пиксели, и не тысячи пикселей, не пункты и не тысячи пунктов и не логические дюймы (с точностью до 10^n) т.к. получается расхождение, описанное в первом сообщении.


Так и спросили бы про это с самого начала, я бы Вас и не грузил тогда

Design units — это условные единицы, в которых разработчик шрифта (точнее, гарнитуры или font family) рисует эту гарнитуру. Единицы эти ни к чему е привязаны и у разных гарнитур могут быть разными, но в пределах однй гарнитуры они гарантированно не меняются.
Гарнитуры рисуются в координатной сетке и design unit — просто шаг этой сетки.
У оригинальных шрифтов высота шрифта обычно выбирается 2-4 тысячи design units, чтобы удобнее было рисовать. У сконвертированных шрифтов из других форматов это могут быть произвольные значения, так как конвертор может всё поменять.
Re[4]: Вопрос по измерению фонтов
От: Andrej-V  
Дата: 13.05.08 22:48
Оценка:
Здравствуйте, vmpire,
Спасибо. Непонятно в каких едмницах Font.Height (=16)?
И что такое 10 в Font f = new Font("Arial", 10); (это не равно ascent+descent пересчитанных в пиксели=11,17187463)
lineSpacing пересчитанное в пиксели равно 11.4990234 — это не равно ни 10 ни 16.


//g -объект Graphics
g.PageUnit = GraphicsUnit.Pixel;
float scale = g.PageScale;//1.0
float xdpi = g.DpiX;//96.0 - количество пикселей на логический дюйм по горизонтали
float ydpi = g.DpiY;//96.0 - количество пикселей на логический дюйм по вертикали

Font f = new Font("Arial", 10);      
                                
int fHeight = f.Height;//16  
           
int lineSpacing = f.FontFamily.GetLineSpacing(FontStyle.Regular);//2355 Design units 
int EmHeight = f.FontFamily.GetEmHeight(FontStyle.Regular);//Design units  2048 
                                            
float lineSpacingPixel = f.Size * lineSpacing / f.FontFamily.GetEmHeight(FontStyle.Regular);//11.4990234
//11.4990234 --высота шрифта в пикселях 

                
int ascent = f.FontFamily.GetCellAscent(FontStyle.Regular);//Design units 1854 (не зависит от буквы)
int descent = f.FontFamily.GetCellDescent(FontStyle.Regular);//Design units 434 (не зависит от буквы)
float ascentPixel = f.Size * ascent / f.FontFamily.GetEmHeight(FontStyle.Regular);//9.052734
float descentPixel = f.Size * descent / f.FontFamily.GetEmHeight(FontStyle.Regular);//2.11914063
//ascentPixel+descentPixel =11,17187463
Re[5]: Вопрос по измерению фонтов
От: vmpire Россия  
Дата: 14.05.08 11:04
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:

AV>Здравствуйте, vmpire,

AV>Спасибо. Непонятно в каких едмницах Font.Height (=16)?
Это интерлиньяж — расстояние между строками. В пикселях.

AV> И что такое 10 в Font f = new Font("Arial", 10); (это не равно ascent+descent пересчитанных в пиксели=11,17187463)

Это em-size — высота строчной буквы m (один из общепринятых размеров шрифта). в point-ах. (1/72 дюйма)
Величина ascent+descent не обязана быть равна ничему, это как спроектирован шрифт, так и будет.
Но логически понятно, что в большинстве нормальных шрифтов она обычно чуть меньше интерлиньяжа.
Посмотрим, чему она равна в пикселях:
(1854+434)*(10/2048)*(1/72)*96 = 14.8958 — так и есть

*(10/2048) — пересчёт em из design units в пойнты
*(1/72) — пересчёт пойнтов в дюймы
*96 — пересчёт дюймов в пиксели (зависит от разрешения)

AV>lineSpacing пересчитанное в пиксели равно 11.4990234 — это не равно ни 10 ни 16.

По Вашей формуле это пересчёт не в пиксели, а в поинты.
Если пересчитать в пиксели, учитывая разрешение Graphics, получим
11.4990234*(1/72)*96 = 15.332
Windows всегда округляет line spacing до целого количества пикселей в большую сторону (), то есть до 16.
Отсюда Font.Height = 16
Re[6]: Вопрос по измерению фонтов
От: Andrej-V  
Дата: 14.05.08 15:23
Оценка:
Здравствуйте, vmpire, Вы писали:

AV>>lineSpacing пересчитанное в пиксели равно 11.4990234 — это не равно ни 10 ни 16.

V>По Вашей формуле это пересчёт не в пиксели, а в поинты.
V>Если пересчитать в пиксели, учитывая разрешение Graphics, получим
V>11.4990234*(1/72)*96 = 15.332
V>Windows всегда округляет line spacing до целого количества пикселей в большую сторону (), то есть до 16.
V>Отсюда Font.Height = 16

Спасибо.
На сей раз меня сбила с толку статья из локальной MSDN "How to: Obtain Font Metrics".
В ней утверждается, что пересчет идет в пиксели. Вот выдержка из этой статьи:

// Display the line spacing in design units and pixels.
lineSpacing = fontFamily.GetLineSpacing(FontStyle.Regular);

// 18.398438 = 16.0 * 2355 / 2048
lineSpacingPixel =
font.Size * lineSpacing / fontFamily.GetEmHeight(FontStyle.Regular);
infoString = "The line spacing is " + lineSpacing + " design units, " +
   lineSpacingPixel + " pixels.";
e.Graphics.DrawString(infoString, font, solidBrush, pointF);

Но теперь ясно, что в статье ошибка.
У меня остались 3-и вопроса
1.Непонятно еще почему так:
// float measureStringHeight = (g.MeasureString("a", f)).Height;//16.5624981 это число не зависит от буквы

Вы же выше получили в пикселях 15.332
2.Подскажите пожалуйста, есть ли какой-нибудь способ определения реальной высоты буквы ("a" и "A" имеют разную высоту)
3.Не могли б еще посказать, что такое EM? В старой книге (в новой про это нет) Троелсена написано, что GetEmHeight() Возвращает квадрат, определенный самой широкой и самой высокой буквами шрифта. Но по логике пересчета из design units в пункты видно, что размерность должна быть [L], а не площадь. Т.е. это, вероятно, наибольшая сторона квадрата. Или я чего-то не понимаю?
Re[7]: Вопрос по измерению фонтов
От: vmpire Россия  
Дата: 14.05.08 16:12
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:

AV>1.Непонятно еще почему так:

AV>
AV>// float measureStringHeight = (g.MeasureString("a", f)).Height;//16.5624981 это число не зависит от буквы
AV>

AV>Вы же выше получили в пикселях 15.332
На этот вопрос я достоверно ответить не могу. В MSDN есть такое:
The MeasureString method is designed for use with individual strings and includes a small amount of extra space before and after the string to allow for overhanging glyphs
То есть, что и как считает MeasureString — не очень понятно. По крайней мере, там есть много опций на эту тему.

AV>2.Подскажите пожалуйста, есть ли какой-нибудь способ определения реальной высоты буквы ("a" и "A" имеют разную высоту)

Не понял вопрос: что есть "реальная" высота? Высоту чего Вы хотите получить и в каких единицах?
Сама по себе буква (точнее, gliph) высоты не имеет (векторная она), за исключением относительных design units. Размер буквы в пикселях, миллиметрах или других единицах зависит от того, куда эта буква выводится.

AV>3.Не могли б еще посказать, что такое EM? В старой книге (в новой про это нет) Троелсена написано, что GetEmHeight() Возвращает квадрат, определенный самой широкой и самой высокой буквами шрифта. Но по логике пересчета из design units в пункты видно, что размерность должна быть [L], а не площадь. Т.е. это, вероятно, наибольшая сторона квадрата. Или я чего-то не понимаю?

Что такое em — достаточно подробно написано в http://en.wikipedia.org/wiki/Em_(typography)
Применительно к компьютерным шрифтам — это, в общем случае, произвольный размер, примерно равный ширине буквы "М".
Что касается Троелсена — я его не читал, но предполагаю, что Вы читали его по русски и имеет место неправильный перевод термина "em-quad".
Что это такое — написано в указанной статье. В этом смысле — это ширина квадрата.
Re[8]: Вопрос по измерению фонтов
От: Andrej-V  
Дата: 14.05.08 20:08
Оценка:
Здравствуйте, vmpire, Вы писали:

V>Не понял вопрос: что есть "реальная" высота? Высоту чего Вы хотите получить и в каких единицах?

V>Сама по себе буква (точнее, gliph) высоты не имеет (векторная она), за исключением относительных design units. Размер буквы в пикселях, миллиметрах или других единицах зависит от того, куда эта буква выводится.
Я нарисовал, что имею в виду. Но к сожалению, кажется, здесь нет возможности добавить рисунок. Поэтому на пальцах. Надо обрамить букву прямоугольником измеряемую букву так, чтобы линии прямоугольника касались видимой части буквы. Это будет не тот прямоугольник, который получают при EM (насколько я понимаю прямоугольник EM больше). Иногда, например, когда нужно нарисовать "а" в степени "в", хорошо бы знать эти величины. А единицы — любые, можно design units.


V>Что такое em — достаточно подробно написано в http://en.wikipedia.org/wiki/Em_(typography)

V>Применительно к компьютерным шрифтам — это, в общем случае, произвольный размер, примерно равный ширине буквы "М".
V>Что касается Троелсена — я его не читал, но предполагаю, что Вы читали его по русски и имеет место неправильный перевод термина "em-quad".
V>Что это такое — написано в указанной статье. В этом смысле — это ширина квадрата.
У меня почему-то не находится статья по указанной Вами ссылки. И потому пока держу версию, что это не ширина квадрата, а наибольшая сторона прямоугольника внутри которого рисуется буква (у буквы "i" это будет высота).
Re[9]: Вопрос по измерению фонтов
От: vmpire Россия  
Дата: 15.05.08 12:49
Оценка: 3 (1)
Здравствуйте, Andrej-V, Вы писали:

AV>Здравствуйте, vmpire, Вы писали:


V>>Не понял вопрос: что есть "реальная" высота? Высоту чего Вы хотите получить и в каких единицах?

V>>Сама по себе буква (точнее, gliph) высоты не имеет (векторная она), за исключением относительных design units. Размер буквы в пикселях, миллиметрах или других единицах зависит от того, куда эта буква выводится.
AV>Я нарисовал, что имею в виду. Но к сожалению, кажется, здесь нет возможности добавить рисунок. Поэтому на пальцах. Надо обрамить букву прямоугольником измеряемую букву так, чтобы линии прямоугольника касались видимой части буквы. Это будет не тот прямоугольник, который получают при EM (насколько я понимаю прямоугольник EM больше). Иногда, например, когда нужно нарисовать "а" в степени "в", хорошо бы знать эти величины. А единицы — любые, можно design units.
Теперь понятно.
В точности того, что Вам нужно, в GDI+ я не нашёл, но думаю, что ближе всего к Вашим потребностям метод MeasureCharacterRanges.
У меня не получилось, чтобы он выдавал горизонтальный размер так, как надо, но возможно, что нужно просто поиграться с опциями.

        private void Form1_Load(object sender, EventArgs e)
        {
            Graphics g = Graphics.FromHwnd(this.Handle);

            Font f = new Font("Arial", 10);
            StringFormat sf = (StringFormat)StringFormat.GenericTypographic.Clone();
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Near;
            sf.Trimming = StringTrimming.None;
            sf.FormatFlags |= StringFormatFlags.NoFontFallback | StringFormatFlags.NoWrap;
            sf.SetMeasurableCharacterRanges(new CharacterRange[] { new CharacterRange(0, 1) });

            Region[] r1 = g.MeasureCharacterRanges("i", f, new RectangleF(0, 0, 100, 100), sf);
            Region[] r2 = g.MeasureCharacterRanges("M", f, new RectangleF(0, 0, 100, 100), sf);
            Region[] r3 = g.MeasureCharacterRanges(".", f, new RectangleF(0, 0, 100, 100), sf);

            RectangleF rect1 = r1[0].GetBounds(g); // {X=0,Y=1,002604,Width=2,96224,Height=14,89583}
            RectangleF rect2 = r2[0].GetBounds(g); // {X=0,Y=1,002604,Width=11,10677,Height=14,89583}
            RectangleF rect3 = r3[0].GetBounds(g); // {X=0,Y=1,002604,Width=3,704427,Height=14,89583}

            return;
        }



V>>Что такое em — достаточно подробно написано в http://en.wikipedia.org/wiki/Em_(typography)

V>>Применительно к компьютерным шрифтам — это, в общем случае, произвольный размер, примерно равный ширине буквы "М".
V>>Что касается Троелсена — я его не читал, но предполагаю, что Вы читали его по русски и имеет место неправильный перевод термина "em-quad".
V>>Что это такое — написано в указанной статье. В этом смысле — это ширина квадрата.
AV>У меня почему-то не находится статья по указанной Вами ссылки. И потому пока держу версию, что это не ширина квадрата, а наибольшая сторона прямоугольника внутри которого рисуется буква (у буквы "i" это будет высота).
Ссылка не находится, потому, что закрывающая скобка не попала в ссылку. Могли бы уж сами поискать слово em.
Re[10]: Вопрос по измерению фонтов
От: Andrej-V  
Дата: 15.05.08 20:31
Оценка:
Здравствуйте, vmpire.
То, что Вы получили, равно сумме ascent+descent, вычисленной в пикселях Вами ранее. Меньше, вроде, играя опциями получить не получится. Можно получить реальные размеры создав Bitmap, нарисовать на нем букву и просканировать начиная сверху полинейно (Bitmap.GetPixel), определяя самые крайние пикселы имеющие цвет не совпадающий с фоном (и создать статический массив размеров). Или, если фонт и размер определен можно просто посмотреть на экран отображающий напечатанный алфавит и посчитать пиксели вручную (внося размеры в массив).
Спасибо большое за помощь.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.