Pas Grafik yerel C++ ve C#paylaşımı Grafik
Şu anda bir Boya .NET benzeri bir uygulama üzerinde çalışıyorum arasında nesne yönetilen ve yönetilmeyen kod arasındaki nesne zaman keskinliği yumuşatma ayarını kaybetmek. C# 'da uygulanan çok sayıda katman katmanım var. Bu katmanlar bir WinForms kullanıcı denetimi tarafından sağlanan bir .NET Graphics nesnesine çizilir - WPF kanvas kontrolüne benzer. aşağıdaki gibi tabaka temel sınıf uygulanan bir Çekme yöntemi vardır:
Ayrıca konik ya da bu gibi etkileri başvuruyorum yana karışık mod düzeneğinin katmanların bileşimin yaptığım performans ve Dekompilasyon sorunları içinpublic void Draw(IntPtr hdc)
{
using (var graphics = Graphics.FromInternalHDC(hdc)
{
// First: Setup rendering settings like SmoothingMode, TextRenderingHint, ...
// Layer specific drawing code goes here...
}
}
Düşen gölge. Tabii ki, C++/CLI ile yazılan sarıcı, doğrudan tuval kontrolünden çağrılır ve her katmanın meta verilerini ve hedef Graphics nesnesini (C# yazılı kanvas kullanıcı kontrolümün Grafik nesnesi) yerel C++ sınıfına iletir.
C++/CLI Sarıcı:
public ref class RendererWrapper
{
public:
void Render(IEnumerable<Layer^>^ layersToDraw, Graphics^ targetGraphics)
{
// 1) For each layer get metadata (position, size AND Draw delegate)
// 2) Send layer metadata to native renderer
// 3) Call native renderer Render(targetGraphics.GetHDC()) method
// 4) Release targetGraphics HDC
};
}
Yerli C++ Renderer: Şimdiye kadar iyi
class NativeRenderer
{
void NativeRenderer::Render(vector<LayerMetaData> metaDataVector, HDC targetGraphicsHDC)
{
Graphics graphics(targetGraphicsHDC);
// Setup rendering settings (SmoothingMode, TextRenderingHint, ...)
for each metaData in metaDataVector
{
// Create bitmap and graphics for current layer
Bitmap* layerBitmap = new Bitmap(metaData.Width, metaData.Height, Format32bppArgb);
Graphics* layerGraphics = new Graphics(layerBitmap);
// Now the interesting interop part
// Get HDC from layerGraphics
HDC lgHDC = layerGraphics->GetHDC();
// Call metaData.Delegate and pass the layerGraphics HDC to C#
// By this call we are ending up in the Draw method of the C# Layer object
metaData.layerDrawDelegate(lgHDC);
// Releasing HDC - leaving interop...
layerGraphics->ReleaseHDC(lgHDC);
// Apply bevel/shadow effects
// Do some other fancy stuff
graphics.DrawImage(layerBitmap, metaData.X, metaData.Y, metaData.Width, metaData.Height);
}
}
}
. Yukarıdaki kod tek şey, örneğin gölgeler ile PNG işlerken benim şu anki uygulama anti-aliasing ve yarı şeffaflık eksik olmasıdır
Sorun
... beklendiği neredeyse çalışır, ancak. Bu yüzden sadece Alfa kanalı için sadece 2 değere sahibim: Şeffaf veya tam görünür 255 Renk. Bu yan etki, alfa kanalı ve yazı tiplerinin çok çirkin görünümlü PNG'lerini çiziyor. Saf C# kodu ile çalışırken daha önce olduğu gibi aynı pürüzsüz ve güzel yarı saydam anti-kenar yumuşatma alamıyorum.
ANCAK: yerli Graphics bir dize çizerken
layerGraphics->DrawString(...);
karşıtı aliasing ve yarı şeffaflık geri iyi içindir, doğrudan nesne. Bu yüzden sorun sadece Grafik HDC’yi .NET’e geçirirken belirgindir.
Sorular
bu soruna bir çözüm/çözüm var mı? Bitmap'i doğrudan C# Layer sınıfında oluşturmaya çalıştım ve HBITMAP için IntPtr'i yerel koda döndürdüm. Bu yaklaşım işe yarıyor, ancak bu durumda HBITMAP'i alfa kanalı ile GDI + Bitmap'e dönüştürmek için mükemmel bir çözüm bulamadığım için başka bir problemim var (yazı çizerken beyaz piksel gürültü kenarları sarar).
Girişiniz için teşekkürler! :)
Demo Çözüm
burada bir demo çözüm bulacağız Ekli: Sources
3 farklı render yöntemleri (bütün NativeRenderer uygulanan test ediyorum bu demo çözümde.CPP), ilki açıklanan problemleri gösterirken:
1) RenderViaBitmapFromCSharp()-a), C++, yeni bir bitmap oluşturur yeni grafik C++ nesne oluşturur, aramalar C++ Grafik geçirerek C# çizim kodu HDC nesne -
Ama başarısız: C++ doğrudan çizimb) çok yaratılan bitmap yoluyla çalışır
2) RenderDirectlyFromCSharp() - Works
3) RenderDirectlyFromCPP (- C++ , C++ Grafik HDC nesne geçirilerek C# çizim kodunu çağırmasını yeni grafik olarak ele C# Graphics nesne oluşturur) - yeni Grafik C++ C# Grafik gelen tanıtıcı nesne oluşturur C++ metni doğrudan çizer - İşleri
C++/CLI kodu biraz ... C# kodu görünüyor P! Neyse, C++ 'da dize yazmak için kullandığınız kodu görmüyorum, bu yüzden biraz tahmin ediyorum: eğer yerel GDI fonksiyonlarını kullanıyorsanız (metaData.layerDrawDelegate (lgHDC) için), o zaman dizge ayarlarla işlenmez. GDI + ile (= şeffaflık, antialias ve GDI + 'dan başka herhangi bir şey GDI çağrısına uygulanmayacak) vardı. –
Daha fazla C++/CLI olması için sözde kodu değiştirdim. Dize yazma yöntemi sadece özel bir şey değil, DrawString MSDN açıklamasından koparıp kopyalanır. Katmanın Çizme yönteminde, SmoothingMode veya TextRenderHint gibi tüm ayarları yerel GDI + nesnesindekiyle aynı olarak ayarlıyorum. – barnacleboy
'ExtTextOut' gibi GDI işlevleri bir alfa kanalı desteklemez ve bir DC ile seçilen bir bitmap'i bir alfa kanalı ile geçirmek, bunları alfa'nın farkında olmalarını sağlamaz. –