Я использую стороннюю библиотеку для рендеринга изображения на GDI DC, и мне нужно убедиться, что любой текст отображается без сглаживания / сглаживания, чтобы я мог преобразовать изображение в предопределенную палитру с индексированными цветами.
Сторонняя библиотека, которую я использую для рендеринга, не поддерживает это и просто отображает текст в соответствии с текущими настройками Windows для рендеринга шрифтов. Они также сказали, что вряд ли они добавят возможность отключать сглаживание в ближайшее время.
Лучшая работа, которую я нашел на данный момент, заключается в том, чтобы вызывать стороннюю библиотеку таким образом (обработка ошибок и предварительные проверки настроек для краткости опущены):
private static void SetFontSmoothing(bool enabled)
{
int pv = 0;
SystemParametersInfo(Spi.SetFontSmoothing, enabled ? 1 : 0, ref pv, Spif.None);
}
// snip
Graphics graphics = Graphics.FromImage(bitmap)
IntPtr deviceContext = graphics.GetHdc();
SetFontSmoothing(false);
thirdPartyComponent.Render(deviceContext);
SetFontSmoothing(true);
Это, очевидно, оказывает ужасное влияние на операционную систему, другие приложения мерцают от включенного cleartype до отключенного и возвращаются каждый раз, когда я рендерирую изображение.
Итак, вопрос в том, знает ли кто-нибудь, как я могу изменить настройки рендеринга шрифта для определенного DC?
Даже если бы я мог просто внести изменения в процесс или конкретный поток, а не повлиять на всю операционную систему, это был бы большой шаг вперед! (Это дало бы мне возможность обрабатывать этот рендеринг в отдельном процессе - результаты все равно записываются на диск после рендеринга)
РЕДАКТИРОВАТЬ: Я хотел бы добавить, что я не против, если решение является более сложным, чем просто несколько вызовов API. Я бы даже был рад решению, которое включало бы перехват системы dll, если бы это было всего лишь около суток работы.
РЕДАКТИРОВАТЬ: Справочная информация
Сторонняя библиотека выполняет рендеринг с использованием около 70 цветов. После рендеринга изображения (которое на самом деле является плиткой карты) в DC, я преобразовываю каждый пиксель из его 32-битного цвета обратно в индекс палитры и сохраняю результат в виде изображения в градациях серого 8bpp. Это загружается на видеокарту в качестве текстуры. Во время рендеринга я повторно применяю палитру (также сохраненную в виде текстуры) с пиксельным шейдером, выполняющимся на видеокарте. Это позволяет мне мгновенно переключаться между различными палитрами, вместо того, чтобы восстанавливать все необходимые плитки. Генерация и загрузка всех плиток для обычного представления о мире занимает от 10 до 60 секунд.
РЕДАКТИРОВАТЬ: переименованный GraphicsDevice to Graphics
Класс GraphicsDevice в предыдущей версии этого вопроса на самом деле является System.Drawing.Graphics. Я переименовал его (используя GraphicsDevice = ...), потому что рассматриваемый код находится в пространстве имен MyCompany.Graphics, и компилятор не смог правильно его разрешить.
РЕДАКТИРОВАТЬ: Успех!
Мне даже удалось перенести приведенную ниже функцию PatchIat
на C # с помощью Marshal.GetFunctionPointerForDelegate
. Команда взаимодействия .NET действительно проделала фантастическую работу! Сейчас я использую следующий синтаксис, где Patch
- это метод расширения для System.Diagnostics.ProcessModule
:
module.Patch(
"Gdi32.dll",
"CreateFontIndirectA",
(CreateFontIndirectA original) => font =>
{
font->lfQuality = NONANTIALIASED_QUALITY;
return original(font);
});
private unsafe delegate IntPtr CreateFontIndirectA(LOGFONTA* lplf);
private const int NONANTIALIASED_QUALITY = 3;
[StructLayout(LayoutKind.Sequential)]
private struct LOGFONTA
{
public int lfHeight;
public int lfWidth;
public int lfEscapement;
public int lfOrientation;
public int lfWeight;
public byte lfItalic;
public byte lfUnderline;
public byte lfStrikeOut;
public byte lfCharSet;
public byte lfOutPrecision;
public byte lfClipPrecision;
public byte lfQuality;
public byte lfPitchAndFamily;
public unsafe fixed sbyte lfFaceName [32];
}