unterschiedliches Verhalten zwischen der Druckvorschau und dem Druckbild auf Papier



  • Hallo,

    ich habe in einer Anwendung das Problem, dass ich ein Icon aus einer Ressource (hier ein LED-Button) laden möchte um ihn dann auszudrucken.```
    ... Code ...

    pDC->SelectObject(&Fettschrift);
    	pDC->TextOut(Druckbereich.left, Druckbereich.top - 1650, _T("aktueller Status (Druckdatum):"));
    	pDC->SelectObject(&Normalschrift);
    	
    	HICON hSymbolLED;
    	switch (m_Faelligkeitendialog.GetState_Maschine())
    	{
    	case GRUEN:
    		hSymbolLED = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_GREEN_ICON));
    		break;
    	case GELB:
    		hSymbolLED = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_YELLOW_ICON));
    		break;
    	case ORANGE:
    		hSymbolLED = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ORANGE_ICON));
    		break;
    	case ROT:
    		hSymbolLED = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_RED_ICON));
    		break;
    	default:
    		hSymbolLED = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_GRAY_ICON));
    	}
    	pDC->DrawIcon(Druckbereich.left + 570, Druckbereich.top - 1650, hSymbolLED);
    

    Der Code funktioniert leider nur in der Druckvorschau. Dort wird der Text und das Icon wie gewünscht an der richtigen Stelle ausgegeben. Beim Druck auf das Papier fehlt das Icon. Warum ist das so bzw. wie kann man das abstellen?



  • Versuche es mal eher mit LoadImage und DrawIconEx. Dein Icon würde auf 32x32 Pixel ausgegeben, das macht bei 600dpi oder höher ein ziemlich kleines Bild.

    Was für einen mapping mode verwendest Du?



  • Ich verwende MM_LOMETRIC. Das scheint das Problem zu sein, da in der MSDN was von MM_TEXT steht. Der pDC aus der OnDraw hat leider keine Methode LoadImage bzw. DrawIconEx, sodass ich das von diesem Gerätekontext losgelöst machen müsste.



  • @andydd sagte in unterschiedliches Verhalten zwischen der Druckvorschau und dem Druckbild auf Papier:

    Der pDC aus der OnDraw hat leider keine Methode LoadImage bzw. DrawIconEx, sodass ich das von diesem Gerätekontext losgelöst machen müsste.

    Wo ist das Problem? LoadIcon() ist doch auch kein Member.



  • @martin-richter Ich hab das jetzt mal mit DrawIconEx ausprobiert. Das Problem ist das gleiche. Hab es mal ganz extrem gemacht und auf das 10fache skaliert. In der Seitenansicht wird es auch 10fach größer dargestellt, auf dem Papier gar nicht.

    DrawIconEx(pDC->GetSafeHdc(), Druckbereich.left + 570, Druckbereich.top - 2100, hSymbolLED, 320, 320, 0, NULL, DI_NORMAL);
    


  • Passen denn die Werte für Druckbereich für beide DC? Evtl. sind dann deine relativen Werte beim Drucken außerhalb?

    Edit:
    Was mir noch einfällt: druckst du denn in Farbe oder ist S/W (bzw. Graustufen) eingestellt (so daß das Icon nicht dargestellt werden kann)? Überprüfe mal den Rückgabewert von LoadDrawIconEx sowie GetLastError().



  • @th69 Die Werte passen. Weitere Textausgaben wie auch Zeichenobjekte werden wie gewünscht gezeichnet. LoadIconEx verwende ich nirgends. LoadIcon gibt auch das richtige Handle zurück, sonst würde es ja auch nicht in der Druckvorschau zu sehen sein. DrawIcon oder DrawIconEx liefern 1 zurück. Der Rückgabewert von GetLastError ist 0.



  • LoadIcon ist dumm und verwendet immer nur die gleiche Auflösung. LoadImage ist da etwas besser und kann eben auch andere (evtl. bessere) Auflösungen in ein Icon laden.

    Ich benutze DrawIcon und Konsorten nie zum drucken, ich verwende immer eine Imagelist. Aber das hilft Dir so auch nicht weiter. Außer Du lädst die Icons in eine Imagelist und druckst aus der.

    Aber selbst mit einer Imagelist drucke ich meistens (so weit ich mich erinnere) erst in einen Memory DC und blitte den auf den Drucker DC. Vielleicht hilft das hier auch.



  • Sorry, meinte natürlich DrawIconEx (bzw. DrawIcon).



  • @martin-richter Ich habe das jetzt mal wie vorgeschlagen mit einer ImageList gemacht.

    HIMAGELIST himlIcons;
    	HICON hicon;          
    
    	InitCommonControls();
    
    	
    	himlIcons = ImageList_Create(32, 32, ILC_MASK, 5, 0);
    
    	hicon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_GREEN_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
    	ImageList_AddIcon(himlIcons, hicon);
    	hicon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_YELLOW_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
    	ImageList_AddIcon(himlIcons, hicon);
    	hicon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ORANGE_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
    	ImageList_AddIcon(himlIcons, hicon);
    	hicon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_RED_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
    	ImageList_AddIcon(himlIcons, hicon);
    	hicon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_GRAY_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
    	ImageList_AddIcon(himlIcons, hicon);
    	
    	ImageList_Draw(himlIcons, 1, pDC->GetSafeHdc(), Druckbereich.left + 570, Druckbereich.top - 2100, ILD_TRANSPARENT);
    	
    	switch (m_Faelligkeitendialog.GetState_Bahnzugmesssystem())
    	{
    	case GRUEN:
    		ImageList_Draw(himlIcons, 0, pDC->GetSafeHdc(), Druckbereich.left + 570, Druckbereich.top - 2100, ILD_TRANSPARENT);
    		break;
    	case GELB:
    		ImageList_Draw(himlIcons, 1, pDC->GetSafeHdc(), Druckbereich.left + 570, Druckbereich.top - 2100, ILD_TRANSPARENT);
    		break;
    	case ORANGE:
    		ImageList_Draw(himlIcons, 2, pDC->GetSafeHdc(), Druckbereich.left + 570, Druckbereich.top - 2100, ILD_TRANSPARENT);
    		break;
    	case ROT:
    		ImageList_Draw(himlIcons, 3, pDC->GetSafeHdc(), Druckbereich.left + 570, Druckbereich.top - 2100, ILD_TRANSPARENT);
    		break;
    	default:
    		ImageList_Draw(himlIcons, 4, pDC->GetSafeHdc(), Druckbereich.left + 570, Druckbereich.top - 2100, ILD_TRANSPARENT);
    	}
    

    Leider gleiches Problem. Gibts da noch einen Tipp? Das mit dem MEMDC würde ich gern probieren, nur muss ich da den gesamten Code umschreiben. Aber noch mal eine Verständnisfrage. Bei der Druckvorschau wird schon der PrinterDC verwendet? m_bPrinting ist nämlich da 1, egal ob die Ausgabe auf Papier oder in der Seitenvorschau. Trotzdem hat ja ein Screen eine andere Auflösung als ein Drucker. Jedoch wird immer in der Literatur davon gesprochen, dass man bei den Zeichenmethoden zwischen der reinen Bildschirmdarstellung und der Ausgabe auf dem Drucker verschieden skalieren muss und ich habe es so verstanden, dass die Druckvorschau die gleiche Auflösung wie der Druck selbst hat. Oder liege ich da falsch?



  • Nein! Der Drucker DC wird nur für die Metric verwendet, die Ausgabe erfolgt natürlich über den DC des Bildschirms...

    Im nachfolgenden Code sind zwar einige structs und Klassen verwendet, die nicht bei Dir definiert sind, aber die Verwendung ist eigentlich klar.
    Das ist Code aus einem Listengenerator, der Icons aus einer ImageList druckt.

    Wie Du an dem Kommentar siehst, habe ich es auch ohne MemDC nicht geschafft 😉

    	// Get the icon rectangle					 
    	rectIcon = CRect(CPoint(pDef->m_nStart+pDef->m_rectMargin.left+rectIcon.left-rectBounds.left,
    							GetCursorPos().y+pDef->m_rectMargin.top+rectIcon.top-rectBounds.top),
    					 rectIcon.Size());
    	// truncate rectangle
    	if (rectIcon.right>pDef->m_nStart+pDef->m_nWidth)
    		rectIcon.right = pDef->m_nStart+pDef->m_nWidth-1;
    
    	// The following code didn't worked on some printers (XP: HPLJ21000)!
    	// I do not know why! So I just changed the code into a bitblt.
    	//
    	//// save DC a clipping region
    	//GetDC()->SaveDC();
    	//GetDC()->IntersectClipRect(rectIcon);
    	//// Get the icon and the offset
    	//pImageList->Draw(GetDC(),item.iImage,rectIcon.TopLeft(),ILD_TRANSPARENT);
    	//// Restore old region
    	//GetDC()->RestoreDC(-1);
    
    	// Create a compatible DC to print the stuff over the memory DC
    	CDC memDC;
    	memDC.CreateCompatibleDC(GetDC());
    
    	// Construct the bitmap object
    	CBitmap bm;
    	VERIFY(bm.CreateCompatibleBitmap(GetDC(),rectIcon.Width(),rectIcon.Height()));
    	CBitmap* pOldBmp= memDC.SelectObject(&bm);
    
    	// Draw icon into this memory dcwith the correct background color
    	memDC.FillSolidRect(0,0,rectIcon.Width(),rectIcon.Height(),GetDC()->GetBkColor());
    
    	// Draw with draw indirect, because I may use an alpha channel too and other
            // trouble we have with pImageList->Draw...
    	// pImageList->Draw(&memDC,item.iImage,CPoint(0,0),ILD_TRANSPARENT);
    	IMAGELISTDRAWPARAMS idp;
    	::ZeroMemory(&idp, sizeof(idp));
    	idp.cbSize   = sizeof(idp);
    	idp.i        = item.iImage;
    	idp.hdcDst   = memDC.GetSafeHdc();
    	idp.x        = 0;
    	idp.y        = 0;
    	idp.cx       = rectIcon.Width();
    	idp.cy       = rectIcon.Height();
    	idp.xBitmap  = 0;
    	idp.yBitmap  = 0;
    	idp.fStyle   = ILD_NORMAL;
    	idp.dwRop    = SRCCOPY;
    	idp.rgbBk	 = CLR_DEFAULT;
    	idp.rgbFg    = CLR_DEFAULT;
    #ifdef USE_32BPP_ARGB_BITMAPS
    	idp.fState   = ILS_ALPHA;
    	idp.Frame    = 255;
    #else
    	idp.fState   = ILS_NORMAL;
    	idp.Frame	 = 0;
    #endif
    	idp.crEffect = CLR_DEFAULT;
    	pImageList->DrawIndirect(&idp);
    
    	// draw the bitmap 
    	GetDC()->BitBlt(rectIcon.left,rectIcon.top,
    					rectIcon.Width(),rectIcon.Height(),
    					&memDC,0,0,SRCCOPY);
    					
    	// restore to prevent memory leaks.
    	memDC.SelectObject(pOldBmp);
    


  • @martin-richter Erst mal vielen Dank für den Code. Werde ich gleich mal ausprobieren. rectIcon enthält somit die Größe des Icons. Muss man hier noch eine Umrechnung DPtoLP machen? Ich habe ja MM_LOMETRIC. Welcher Modus kam denn bei dem Beispiel zur Anwendung? Aber dieser Code soll auch wenns nur Auszüge sind funktioniert haben? CreateCompatibleDC erwartet einen CDC* als Übergabeparameter, GetDC liefert aber ein HDC. Aber ohne MemDC liefs anscheinend nicht auf allen Druckern. Dort war es aber bestimmt so, dass sowohl Vorschau wie auch Druck nicht funktionierten. Ich probiere das aktuell mit einem PDF-Drucker, damit ich noch ein wenig den Wald schone. Abgebrannt ist ja in der letzten Zeit schon viel zu viel... 🙂



  • Also habe das mal ausprobiert. Gleiches Verhalen wie vorher. Zusätzlich wird in der Vorschau das Icon verzerrt dargestellt. Ich vermute das hat mit dem Mapping-Mode zu tun. Wäre die Frage ob kurzzeitiges Umschalten auf MM_TEXT was bringt. Leider muss man dann auch alle Koordinaten neu bestimmen.... 😞



  • So, nach etwas hin und her probieren habe ich das jetzt wie folgt lauffähig bekommen (habe nur ILC_MASK gegen ILC_COLOR getauscht):

    CImageList ImageList;
    	ImageList.Create(64, 64, ILC_COLOR, 5, 0);
    	ImageList.Add((HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_GREEN_ICON), IMAGE_ICON, 32, 32, LR_LOADTRANSPARENT));
    	ImageList.Add((HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_YELLOW_ICON), IMAGE_ICON, 32, 32, LR_LOADTRANSPARENT));
    	ImageList.Add((HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ORANGE_ICON), IMAGE_ICON, 32, 32, LR_LOADTRANSPARENT));
    	ImageList.Add((HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_RED_ICON), IMAGE_ICON, 32, 32, LR_LOADTRANSPARENT));
    	ImageList.Add((HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_GRAY_ICON), IMAGE_ICON, 32, 32, LR_LOADTRANSPARENT));
    	
    	switch (m_Faelligkeitendialog.GetState_Bahnzugmesssystem())
    	{
    	case GRUEN:
    		ImageList.Draw(pDC, 0, CPoint(Druckbereich.left + 570, Druckbereich.top - 2100 - 16), ILD_TRANSPARENT);
    		break;
    	case GELB:
    		ImageList.Draw(pDC, 1, CPoint(Druckbereich.left + 570, Druckbereich.top - 2100 - 16), ILD_TRANSPARENT);
    		break;
    	case ORANGE:
    		ImageList.Draw(pDC, 2, CPoint(Druckbereich.left + 570, Druckbereich.top - 2100 - 16), ILD_TRANSPARENT);
    		break;
    	case ROT:
    		ImageList.Draw(pDC, 3, CPoint(Druckbereich.left + 570, Druckbereich.top - 2100 - 16), ILD_TRANSPARENT);
    		break;
    	default:
    		ImageList.Draw(pDC, 4, CPoint(Druckbereich.left + 570, Druckbereich.top - 2100 - 16), ILD_TRANSPARENT);
    		}