Я использую стороннюю библиотеку для рендеринга изображения в GDI DC, и мне нужно убедиться, что любой текст отображается без сглаживания/сглаживания, чтобы я мог преобразовать изображение в предопределенная палитра с индексированными цветами.Отключить сглаживание для определенного контекста устройства GDI
Сторонняя библиотека, которую я использую для рендеринга, не поддерживает это и просто визуализирует текст в соответствии с текущими настройками 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?
Даже если бы я мог просто сделать процесс изменений или конкретный поток, а не влиять на всю операционную систему, это было бы большим шагом вперед! (Это дало бы мне возможность обрабатывать этот рендеринг в отдельном процессе - результаты записываются на диск после рендеринга в любом случае)
EDIT: Я хотел бы добавить, что я не против, если решение сложнее, чем просто несколько вызовов API. Я даже был бы доволен решением, связанным с подключением системных DLL-систем, если бы это работало всего на несколько дней.
EDIT: информация о форекс Сторонняя библиотека отображает с использованием палитры около 70 цветов. После того, как изображение (которое на самом деле является плитой карты) передается в DC, я конвертирую каждый пиксель из его 32-битного цвета обратно в индекс его палитры и сохраняю результат как изображение с серой шкалой 8bpp. Это загружается на видеокарту в виде текстуры. Во время рендеринга я снова применяю палитру (также сохраненную как текстуру) с помощью пиксельного шейдера, выполняемого на видеокарте. Это позволяет мне мгновенно переключаться и исчезать между разными палитрами вместо необходимости регенерировать все необходимые плитки. Для создания и загрузки всех фрагментов для типичного представления мира требуется от 10 до 60 секунд.
EDIT: Переименован GraphicsDevice к Graphics Класс GraphicsDevice в предыдущей версии этого вопроса на самом деле System.Drawing.Graphics. Я переименовал его (используя GraphicsDevice = ...), потому что данный код находится в пространстве имен MyCompany.Graphics, и компилятор не смог его правильно решить.
EDIT: Success! Мне даже удалось установить функцию PatchIat
ниже на C# с помощью Marshal.GetFunctionPointerForDelegate
. Команда .NET interop действительно сделала фантастическую работу! Я сейчас, используя следующий синтаксис, где 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];
}
, если этот код решил проблему, вы должны, вероятно, отметьте свой собственный ответ как принятый ответ. –
@ Юстин, да, хорошая точка. Как вы можете видеть из дат, я не добавлял код C# до года спустя, поэтому я не думал об этом делать в то время. Надеюсь, что @ Chris Becke не потеряет репутацию для ответа, который был переназначен, я бы никогда не решил эту проблему без его помощи. –
Молодцы! Обратите внимание, что это также работает на платформе x64, но вам нужно немного изменить структуру ImageOptionalHeader, поскольку поле _BaseOfData_ отсутствует в IMAGE_OPTIONAL_HEADER64. – Poustic