我使用一个第三方库图像呈现给GDI DC我需要确保任何文本中呈现,没有任何平滑/antialiasing这样我可以把图像到预定的调色板与编制索引的颜色。

第三方图书馆我用用于呈现不支持这只是使文本按当前的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);

这显然有一个可怕的影响的操作系统、其他应用程序的闪烁,从明确的类型启用无障碍和后我每次呈现的形象。

所以问题是,任何人都不会知道我怎么可以改变的字体渲染的设置一个特定的DC?

甚至如果我可能只使变革进程或线的特定而不是影响到整个操作系统,这将是向前迈出的一大步!(这会给我选择的农耕,这呈现出一个独立的过程的结果写入磁盘之后,呈现无论如何)

编辑: 我想补充的是,我不介意的解决方案更加复杂的不仅仅是一个几API话。我甚至是满意的解决方案的参与挂钩的系统dll如果它是只有一天的工作。

编辑:背景信息 第三方图书馆使用的调色板的大约70颜色。以后的图像(其中实际上是一个地图瓦)呈现的DC,我把每一像素的32位色回这是调色板索引和储存的结果作为一个8bpp灰度图像。这是上传的视频片作为一个纹理。在渲染过程中,我重新申请的调色板(也存储为一个纹)与一个素的色器上执行的视频卡。这让我开关和褪色之间不同的调色板瞬间,而不是需要重新产生所有需要的瓷砖。它需要之间的10-60秒的生成和传所有的瓷砖个典型的世界观。

编辑:改名为GraphicsDevice以图形 类GraphicsDevice在以前的版本的这个问题实际上是系统。图。图形。我已经改名为(使用GraphicsDevice=...)因代码在的问题是在空间(.图形和编译器不能解决它。

编辑:成功! 我甚至管理端口 PatchIat 功能下文C#有帮助的 Marshal.GetFunctionPointerForDelegate.。净互操作队真的做了出色的工作!我现在使用以下法, 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];
}
有帮助吗?

解决方案 2

按照要求,我已经打包起码我写的解决这个问题,并把它放在一个想库: http://github.com/jystic/patch-iat

它看起来像一个很大的代码,因为我不得不再现的所有Win32结构对于这些东西的工作,而且当时我选择了把每一个在其自己的文件。

如果你想要直接去肉的代码它是在: ImportAddressTable.cs

它的授权非常自由,是所有意图和目的,公共领域,可以随意使用其中的任何项目。

其他提示

不幸的是你不能。控制字体抗锯齿的能力是按字体完成的。GDI 调用 CreateFontIndirect 处理 LOGFONT 结构的成员,以确定是否允许使用cleartype、常规或无抗锯齿。

正如您所指出的,存在系统范围的设置。不幸的是,如果您无法控制 LOGFONT 的内容,则更改系统范围的设置几乎是降低 DC 上字体渲染质量的唯一(已记录的)方法。


这段代码不是我的。不受管理 C.如果您知道其 HMODULE,则会挂钩 dll 或 exe 文件导入的任何函数。

#define PtrFromRva( base, rva ) ( ( ( PBYTE ) base ) + rva )

/*++
  Routine Description:
    Replace the function pointer in a module's IAT.

  Parameters:
    Module              - Module to use IAT from.
    ImportedModuleName  - Name of imported DLL from which
                          function is imported.
    ImportedProcName    - Name of imported function.
    AlternateProc       - Function to be written to IAT.
    OldProc             - Original function.

  Return Value:
    S_OK on success.
    (any HRESULT) on failure.
--*/
HRESULT PatchIat(
  __in HMODULE Module,
  __in PSTR ImportedModuleName,
  __in PSTR ImportedProcName,
  __in PVOID AlternateProc,
  __out_opt PVOID *OldProc
  )
{
  PIMAGE_DOS_HEADER DosHeader = ( PIMAGE_DOS_HEADER ) Module;
  PIMAGE_NT_HEADERS NtHeader;
  PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  UINT Index;

  assert( Module );
  assert( ImportedModuleName );
  assert( ImportedProcName );
  assert( AlternateProc );

  NtHeader = ( PIMAGE_NT_HEADERS )
    PtrFromRva( DosHeader, DosHeader->e_lfanew );
  if( IMAGE_NT_SIGNATURE != NtHeader->Signature )
  {
    return HRESULT_FROM_WIN32( ERROR_BAD_EXE_FORMAT );
  }

  ImportDescriptor = ( PIMAGE_IMPORT_DESCRIPTOR )
    PtrFromRva( DosHeader,
      NtHeader->OptionalHeader.DataDirectory
        [ IMAGE_DIRECTORY_ENTRY_IMPORT ].VirtualAddress );

  //
  // Iterate over import descriptors/DLLs.
  //
  for ( Index = 0;
        ImportDescriptor[ Index ].Characteristics != 0;
        Index++ )
  {
    PSTR dllName = ( PSTR )
      PtrFromRva( DosHeader, ImportDescriptor[ Index ].Name );

    if ( 0 == _strcmpi( dllName, ImportedModuleName ) )
    {
      //
      // This the DLL we are after.
      //
      PIMAGE_THUNK_DATA Thunk;
      PIMAGE_THUNK_DATA OrigThunk;

      if ( ! ImportDescriptor[ Index ].FirstThunk ||
         ! ImportDescriptor[ Index ].OriginalFirstThunk )
      {
        return E_INVALIDARG;
      }

      Thunk = ( PIMAGE_THUNK_DATA )
        PtrFromRva( DosHeader,
          ImportDescriptor[ Index ].FirstThunk );
      OrigThunk = ( PIMAGE_THUNK_DATA )
        PtrFromRva( DosHeader,
          ImportDescriptor[ Index ].OriginalFirstThunk );

      for ( ; OrigThunk->u1.Function != NULL;
              OrigThunk++, Thunk++ )
      {
        if ( OrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG )
        {
          //
          // Ordinal import - we can handle named imports
          // ony, so skip it.
          //
          continue;
        }

        PIMAGE_IMPORT_BY_NAME import = ( PIMAGE_IMPORT_BY_NAME )
          PtrFromRva( DosHeader, OrigThunk->u1.AddressOfData );

        if ( 0 == strcmp( ImportedProcName,
                              ( char* ) import->Name ) )
        {
          //
          // Proc found, patch it.
          //
          DWORD junk;
          MEMORY_BASIC_INFORMATION thunkMemInfo;

          //
          // Make page writable.
          //
          VirtualQuery(
            Thunk,
            &thunkMemInfo,
            sizeof( MEMORY_BASIC_INFORMATION ) );
          if ( ! VirtualProtect(
            thunkMemInfo.BaseAddress,
            thunkMemInfo.RegionSize,
            PAGE_EXECUTE_READWRITE,
            &thunkMemInfo.Protect ) )
          {
            return HRESULT_FROM_WIN32( GetLastError() );
          }

          //
          // Replace function pointers (non-atomically).
          //
          if ( OldProc )
          {
            *OldProc = ( PVOID ) ( DWORD_PTR )
                Thunk->u1.Function;
          }
#ifdef _WIN64
          Thunk->u1.Function = ( ULONGLONG ) ( DWORD_PTR )
              AlternateProc;
#else
          Thunk->u1.Function = ( DWORD ) ( DWORD_PTR )
              AlternateProc;
#endif
          //
          // Restore page protection.
          //
          if ( ! VirtualProtect(
            thunkMemInfo.BaseAddress,
            thunkMemInfo.RegionSize,
            thunkMemInfo.Protect,
            &junk ) )
          {
            return HRESULT_FROM_WIN32( GetLastError() );
          }

          return S_OK;
        }
      }

      //
      // Import not found.
      //
      return HRESULT_FROM_WIN32( ERROR_PROC_NOT_FOUND );
    }
  }

  //
  // DLL not found.
  //
  return HRESULT_FROM_WIN32( ERROR_MOD_NOT_FOUND );
}

您可以通过执行类似的操作从代码中调用它(我没有检查这是否以任何方式编译:P):

  1. 声明一个指向要挂钩的函数的指针类型:

    typedef FARPROC (WINAPI* PFNCreateFontIndirect)(LOGFONT*);
    
  2. 实现一个钩子函数

    static PFNCreateFontIndirect OldCreateFontIndirect = NULL;
    
    WINAPI MyNewCreateFontIndirectCall(LOGFONT* plf)
    {
      // do stuff to plf (probably better to create a copy than tamper with passed in struct)
      // chain to old proc
      if(OldCreateFontIndirect)
        return OldCreateFontIndirect(plf);
    }
    
  3. 在初始化期间的某个时候挂钩该函数

    HMODULE h = LoadLibrary(TEXT("OtherDll"));
    PatchIat(h, "USER32.DLL", "CreateFontIndirectW", MyNewCreateFontIndirectProc, (void**)&OldCreateFontIndirectProc);
    

当然,如果您要挂钩的模块存在于 .NET 领域,则很难确定该模块在哪里 CreateFontIndirect 呼叫将源自。 mscoree.dll?您调用的实际模块?我想祝你好运:P

你需要比黑白您的字体颜色吗? 如果没有,你可以让你的的位图的对象在每个像素的1位图像( Format1bppIndexed 的?)。

该系统将可能对1bpp映射图像不平滑字体呈现。

是的GraphicsDevice类第三方类?

我会做到这一点的方法是:

Graphics g = Graphics.FromImage(memImg);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;

或在您的情况:

GraphicsDevice graphics = GraphicsDevice.FromImage(bitmap)
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;

如果GraphicsDevice的类继承的Graphics类(否则尝试使用Graphics类?)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top