سؤال

أنا باستخدام طرف ثالث مكتبة لتقديم صورة إلى 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 تمكين المعوقين والعودة في كل مرة كنت جعل الصورة.

لذا فإن السؤال هو, لا أحد يعرف كيف يمكن أن يغير الخط إعدادات محددة من العاصمة ؟

حتى إذا أنا فقط يمكن أن تجعل التغييرات عملية أو موضوع محدد بدلا من التي تؤثر على كل نظام التشغيل هذا سيكون خطوة كبيرة إلى الأمام!(أن تعطيني خيار الزراعة هذا يرجع إلى عملية منفصلة - النتائج التي يتم كتابتها إلى القرص بعد التقديم على أي حال)

تحرير: أود أن أضيف أنني لا أمانع إذا كان هذا الحل هو أكثر تعقيدا من مجرد عدد قليل من المكالمات API.حتى تكون سعيدا مع الحل الذي تشارك تركيب النظام dll إذا كان فقط عن أيام العمل.

تحرير:معلومات أساسية مكتبة طرف ثالث يجعل باستخدام لوحة من حوالي 70 الألوان.بعد الصورة (التي هي في الواقع خريطة البلاط) هو المقدمة إلى DC, تحويل كل بكسل من 32 بت اللون مرة أخرى إلى لوحة مؤشر و تخزين النتيجة كما 8bpp اللون الرمادي الصورة.هذا هو تحميلها إلى بطاقة الفيديو الملمس.أثناء التقديم ، أعيد تطبيق لوحة (أيضا تخزين الملمس) مع تظليل بكسل المنفذة على بطاقة الفيديو.هذا يسمح لي أن التبديل تتلاشى بين مختلف لوحات الفور بدلا من الحاجة إلى تجديد كل المطلوب من البلاط.يستغرق ما بين 10-60 ثانية لتوليد وتحميل كل البلاط من أجل عرض نموذجي من العالم.

تحرير:سميت GraphicsDevice الرسومات الطبقة GraphicsDevice في النسخة السابقة من هذا السؤال هو في الواقع نظام.الرسم.الرسومات.كان لي تسميته (باستخدام GraphicsDevice = ...) لأن الرمز في السؤال هو في مساحة الاسم MyCompany.الرسومات و المترجم لم يكن قادرا على حلها بشكل صحيح.

تحرير:النجاح! حتى أنني تمكنت من ميناء PatchIat وظيفة أدناه إلى C# مع مساعدة من Marshal.GetFunctionPointerForDelegate.على .صافي 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];
}
هل كانت مفيدة؟

المحلول 2

كما طلبت أنا قد حزم رمز كتبت لحل هذه المشكلة ووضعها في github: http://github.com/jystic/patch-iat

يبدو أن الكثير من التعليمات البرمجية لأنه كان تتكاثر في كل Win32 هياكل هذه الأشياء إلى العمل في الوقت الذي اختار أن يضع كل واحد في ملف خاص به.

إذا كنت تريد أن تذهب مباشرة إلى اللحوم من المدونة أنه في: ImportAddressTable.cs

انها مرخصة بحرية جدا و هو لجميع المقاصد والأغراض, المجال العام, لذلك لا تتردد في استخدامها في أي مشروع تريد.

نصائح أخرى

للأسف كنت غير قادر.القدرة على التحكم في الخط مكافحة التعرج هو به في الخط.GDI دعوة CreateFontIndirect العمليات أعضاء LOGFONT البنية لتحديد ما إذا كان يسمح استخدام cleartype العادية أو أي مضاد التعرج.

هناك كما ذكرت ، منظومة واسعة من الإعدادات.للأسف تغيير منظومة الإعداد تقريبا فقط (موثقة) وسيلة إلى تقليله نوعية الخط التقديم على DC إذا كنت لا تستطيع التحكم في محتويات LOGFONT.


هذه المدونة ليست لي.هو غير المدارة C.و سوف هوك أي وظيفة المستوردة من قبل dll أو exe الملف إذا كنت تعرف HMODULE.

#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. يعلن مؤشر نوع funciton تريد هوك:

    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);
    

طبعا أنا وحدة كنت تركيب موجود في .صافي الأراضي جدا من غير الواضح إلى أين CreateFontIndirect الاتصال هو الذهاب إلى مصدرها. mscoree.dll?الفعلية وحدة تتصل ؟ بالتوفيق اعتقد :P

هل تحتاجون إلى المزيد من الألوان من الأبيض والأسود على الخطوط ؟ إن لم يكن, يمكنك أن تجعل الخاصة بك نقطية الكائن 1 بت لكل بكسل صورة (Format1bppIndexed?).

النظام ربما ليس على نحو سلس جعل الخط على 1bpp الصور.

هو GraphicsDevice الدرجة 3rd الطرف الصف ؟

الطريقة التي أود أن تفعل هذا:

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 الدرجة يرث رسومات الفئة (وإلا حاول استخدام الرسومات الصف؟)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top