GDI+/.NET шрифты, узнать информацию о конкретном wchar_t
От: _Winnie Россия C++.freerun
Дата: 27.08.05 18:47
Оценка:
Это кросспостинг, так как .NET шрифты и GDI шрифты, как я понял из MSDN почти одно и тоже.

Нужно написать программу по конвертации любого шрифта в свой растровый формат. Читаю MSDN по этому поводу.
Как это лучше сделать?

Можно узнать у FontFamily высоту (GetEmHeight) шрифта (еще не пробовал), высоту нижней части букв (GetCellDescent), высоту от строки написания до самой верхушки буквы(GetCellAscent).
1) Чем отличается EmHeight от суммы Descent и Ascent? Что такое EmHeight(em size)!? Часто упоминается, но не объясняется.

2)Что такое Design Units, как их перевести в пиксели (или другие GraphicsUnits)?
Есть предположение, что можно создать конкретный Font объект, узнать его LineSpacing в пикселях, разделить его на LineSpacing в DesignUnits FontFamily и получить таким образом соотношение между DesignUnits и пикселями. Но как-то это криво выглядит.

3)Как узнать ширину конкретного char (Скажем, CharWidth)?

Как мне заполнить массив byte [(CellDescent+CellAscent) * CharWidth] изображением конкретного char? Можно нарисовать в Graphics, но тут у меня возникает два вопроса:
4)Как создать этот Graphics?
5) Как эффективно получить обратно изображение из Graphics? (В массив байтов).
Правильно работающая программа — просто частный случай Undefined Behavior
Re: GDI+/.NET шрифты, узнать информацию о конкретном wchar_t
От: Кодёнок  
Дата: 29.08.05 13:08
Оценка: 4 (1)
Здравствуйте, _Winnie, Вы писали:

_W>Это кросспостинг, так как .NET шрифты и GDI шрифты, как я понял из MSDN почти одно и тоже.


_W>Нужно написать программу по конвертации любого шрифта в свой растровый формат. Читаю MSDN по этому поводу.

_W>Как это лучше сделать?

Вот тут немного есть: http://www.microsoft.com/typography/otspec/TTCH01.htm

Достаточно много написано в MSDN в разделе Font and Text (Windows GDI).

_W>Можно узнать у FontFamily высоту (GetEmHeight) шрифта (еще не пробовал), высоту нижней части букв (GetCellDescent), высоту от строки написания до самой верхушки буквы(GetCellAscent).

_W>1) Чем отличается EmHeight от суммы Descent и Ascent? Что такое EmHeight(em size)!? Часто упоминается, но не объясняется.
_W>2)Что такое Design Units, как их перевести в пиксели (или другие GraphicsUnits)?

EM Square, Em Height — это квадрат, измеряется в Design Units, которые ничего не значат. Нужен просто чтобы задать какую-то систему измерения. Допустим, EM Size = 2048 Design Units. Это ничего фактически не означает

EM Height = Ascent + Descent + еще кое-что (diacritics etc). AKA Character Cell Height

Body = Ascent + Descent

Ascent = обычно это высота буквы M или A над базовой линией.

Descent = насколько хвост букв y или g вылазит под базовую линию.

_W>3)Как узнать ширину конкретного char (Скажем, CharWidth)?


Тут сложнее всего. В шрифте нет символов, а есть глифы. Для наших языков, один символ = один глиф, НО! иногда буквы могут сливаться, например, в английском:

1) fl -> fl (\uFB02)
2) fi -> fi (\uFB01)
3) AE -> Æ (\u00C6)

В арабском ширина зависит от настроек justification слов в строке, и некоторых дополнительных параметров.

В хинди, санскрите, один, два или три WCHAR могут дать один глиф, сформированный хитрым образом из фрагментов.

Короче, в общем случае, 1 WCHAR может дать 1, 2, 3 или больше глифов, 2 WCHAR могут дать 1, 2, 3 или больше, 3 WCHAR могут дать 1, 2, 3 или больше, и т.д.

Если ты можешь ограничиться языками типа английского, с посимвольным выводом текста, без слияний, кернинга и прочих красивостей, то ширина символа определяется тремя числами (называется ABC), а не одним. A и C могут быть отрицательными и нецелыми.

_W>Как мне заполнить массив byte [(CellDescent+CellAscent) * CharWidth] изображением конкретного char? Можно нарисовать в Graphics, но тут у меня возникает два вопроса:

_W>4)Как создать этот Graphics?
_W>5) Как эффективно получить обратно изображение из Graphics? (В массив байтов).

Выбери кодировку, в которой ты будешь писать (я надеюсь, тебе нужны не все символы из Unicode 4.0? ). Нарисуй каждый символ (либо без сглаживания, либо также формируй альфа-канал) из неё куда-нибудь в центр большого битмапа. У этого текста тебе нужно узнать ABC (GetCharABCWidths). Из ABC ты сможешь узнать ширину символа, а также как его выводить на экран (при условии, что текст можно выводить посимвольно, как русский или английский). Для каждого символа ты запоминаешь
1. A, B, C
2. Картинку размером (в пикселях) Font Height * B.

Если ты рисовал символ в позиции (x, y) = (100, 100) шрифтом размером 14 пикселей, то ты запоминаешь прямогульник (TRUNC(x + A), y, ROUND(x + A + B), y + 14)
Re[2]: GDI+/.NET шрифты, узнать информацию о конкретном wcha
От: _Winnie Россия C++.freerun
Дата: 03.09.05 18:12
Оценка:
Здравствуйте, Кодёнок, Вы писали:

Кё>Здравствуйте, _Winnie, Вы писали:


Кё>Если ты рисовал символ в позиции (x, y) = (100, 100) шрифтом размером 14 пикселей, то ты запоминаешь прямогульник (TRUNC(x + A), y, ROUND(x + A + B), y + 14)



Спасибо большое за информацию, я узнал много интересного.
Не получается.
Когда я рисую одну букву, она отодвигается с некоторым полем, гораздо большим чем AWidth.
Я рисую текст в точке (N,N), затем рисую вертикальные линии в горизонталях N, N+A, N+A+B, N+A+B+C.
Вот что получается:


Как либо узнать, чему равен отступ, либо избавиться от него?

И еще, где узнать где у нарисованой буквы находится baseline?

Вот исходник:


#using <mscorlib.dll>
#using <System.Drawing.dll>
#using <System.dll>

#include <windows.h>
#include <windowsx.h>

using namespace System;
using namespace System::Drawing;
using namespace System::Drawing::Imaging;

int main()
{
    wchar_t Char = L'8';

    const int MaxSize = 100;

    Font *pFont = new Font("Times New Roman", 48);

    Bitmap *pBitmap = new Bitmap(2*MaxSize, 2*MaxSize, PixelFormat::Format32bppArgb);

    Graphics *pG = Graphics::FromImage(pBitmap);
    Brush *pBrush = new SolidBrush(Color::FromArgb(255, 255, 255, 255));

    pG->Clear(Color::FromArgb(0, 0, 0, 0));
    pG->DrawString(
        new String(Char, 1), pFont, pBrush, (float)MaxSize, (float)MaxSize);


    float A_Width, B_Width, C_Width;
    {
        IntPtr IntPtrHdc = pG->GetHdc();
        try
        {
            HDC hdc = (HDC)IntPtrHdc.ToPointer();
            HFONT hfont = (HFONT)pFont->ToHfont().ToPointer();
            SelectFont(hdc, hfont);
            ABCFLOAT ABCWidth;
            if (!GetCharABCWidthsFloat(hdc, Char, Char, &ABCWidth))
                throw new System::Exception(S"GetCharABCWidthsFloat failed");

            A_Width = ABCWidth.abcfA;
            B_Width = ABCWidth.abcfB;
            C_Width = ABCWidth.abcfC;
        }
        __finally
        {
            pG->ReleaseHdc(IntPtrHdc);
        }
    }

    {
#define DRAW_VERTICAL_LINE(X) \
            pG->DrawLine(\
                new Pen(Color::Red), \
                (float)(X), (float)MaxSize, (float)(X), (float)MaxSize + 80);

            DRAW_VERTICAL_LINE(MaxSize);
            DRAW_VERTICAL_LINE(MaxSize+A_Width);
            DRAW_VERTICAL_LINE(MaxSize+A_Width + B_Width);
            DRAW_VERTICAL_LINE(MaxSize+A_Width+ B_Width + C_Width);
    }

    pBitmap->Save(S"8.bmp", ImageFormat::Bmp);
}
Правильно работающая программа — просто частный случай Undefined Behavior
Re[3]: GDI+/.NET шрифты, узнать информацию о конкретном wcha
От: _Winnie Россия C++.freerun
Дата: 03.09.05 21:12
Оценка:
Здравствуйте, _Winnie, Вы писали:

_W>Здравствуйте, Кодёнок, Вы писали:


Кё>>Здравствуйте, _Winnie, Вы писали:


_W>Когда я рисую одну букву, она отодвигается с некоторым полем, гораздо большим чем AWidth.

_W>Я рисую текст в точке (N,N), затем рисую вертикальные линии в горизонталях N, N+A, N+A+B, N+A+B+C.
_W>Вот что получается:

_W>



Вроде, нашел виновника.
Если вместо .NET фукнции Graphics::DrawString использовать WinApi функцию ::TextOutW, то буква ровно ложится в проведенные линии. Но мне не хочется ее использовать, потому что, похоже, API-Brushes не умеют использовать alpha — канал и нельзя сконвертировать .NET brush в HBRUSH.
Как заставить DrawString рисовать как TextOutW? Почему есть разница и откуда смещение?
Правильно работающая программа — просто частный случай Undefined Behavior
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.