2013-03-01 87 views
4

我在將圖像打印到打印機設備上下文(真實或XPS文檔編寫器)時遇到問題。它們在屏幕上下文和打印預覽中很好地工作,但是當我將其打印到文件或打印機時,它們在位於另一個圖像上方時顯示爲黑色方塊。我用的的CImage ::繪製之前和也有類似的結果(黑色或透明正方形)作爲使用THES GDI + API直接:ATL :: CImage似乎在某些設備上歪曲每個像素的Alpha圖像

Gdiplus::Graphics g(hDestDC) ; 
    ... 
    // Edit: the image value here was one aquired from a ATL::CImage not 
    // a Gdiplus::Image (see solution) 
    g.DrawImage(image,rect,0,0,GetWidth(),GetHeight(),Gdiplus::UnitPixel,0,0,0); 

帽似乎表明上下文支持通過

GetDeviceCaps(hDestDC, SB_PIXEL_ALPHA) 
混合的裝置

圖像的性質似乎並沒有任何關係,在這裏我使用了兩個格式:

PNG image data, 256 x 256, 8-bit/color RGBA, non-interlaced 
PNG image data, 192 x 64, 1-bit colormap, non-interlaced 

產量都使用GDI +接口與數據的CImage相同的結果。讓alpha圖像在打印環境中的行爲與屏幕上的行爲一樣的最佳方式是什麼?設備功能是否會誤導某些東西,因爲alpha通過使用BitmapMatrix並使用整個圖像的混合來工作?

編輯:2013年3月4日

我的新的方法是做所有的alpha混合在內存中我的想法是,如果打印機不支持alpha混合我會創造一個內存上下文中混合,然後只需將混合結果複製到上下文中。代碼的重要部分是這樣的:

int width = rectDest.right - rectDest.left; 
int height = rectDest.bottom - rectDest.top; 

BLENDFUNCTION blendFunction; 
blendFunction.BlendOp = AC_SRC_OVER; 
blendFunction.BlendFlags = 0; 
blendFunction.SourceConstantAlpha = 0xFF; 
blendFunction.AlphaFormat = AC_SRC_ALPHA; 

HDC memDC = CreateCompatibleDC(hDestDC); 
HBITMAP bitmap = CreateCompatibleBitmap(hDestDC,width,height); 

SelectBitmap(memDC,bitmap); 
//sample the underying area and copy it to memDC 
::BitBlt(memDC, 0,0, width, height, hDestDC, rectDest.left, rectDest.top, SRCCOPY); 
//now blend the image in memory onto the area. 
GdiAlphaBlend(memDC,0,0, width, height,GetDC(), 0, 0, GetWidth(), GetHeight(),blendFunction); 
//now just BitBlt the blended data to the context 
::BitBlt(hDestDC,rectDest.left, rectDest.top,width,height,memDC,0,0,SRCCOPY); 

......令我驚訝的是,我得到了幾乎相同的結果。實際上,我沿着屏幕左側的中間步驟來確保一切正常。它所抓取的背景和alpha混合結果(即我對打印機上下文的blit)在屏幕上看起來都很棒。這可能是一個錯誤?我猜想BitBlt保留了先前混合的alpha值,所以它是拋出打印機設備上下文的像素數據中的實際alpha值?如果是這樣,我怎麼能在最終的BitBlt之前刪除alpha?

編輯:2013年3月5日
現在,我已經試過如下:
1.使用設備無關位圖來創建HBITMAP參考。
2.使用CreateDiscardableBitmap創建HBITMAP(最成功)。
3.手動設定爲每個像素到0xFF和0×00的alpha通道。

BITMAPINFO bitmapInfo; 
ZeroMemory(&bitmapInfo, sizeof(BITMAPINFO)); 
bitmapInfo.bmiHeader.biBitCount = 32; 
bitmapInfo.bmiHeader.biCompression = BI_RGB; 
bitmapInfo.bmiHeader.biPlanes = 1; 
bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader); 
bitmapInfo.bmiHeader.biWidth = width; 
bitmapInfo.bmiHeader.biHeight = height; 
bitmapInfo.bmiHeader.biSizeImage = bitmapSizeBytes; 

HDC memDC = CreateCompatibleDC(hDestDC); 
//was HBITMAP bitmap = CreateCompatibleBitmap(hDestDC,width,height); 
//also tried HBITMAP bitmap = CreateDiscardableBitmap(hDestDC,width, height); 
HBITMAP bitmap = CreateDIBSection(memDC, &bitmapInfo,DIB_RGB_COLORS,&imageBits,NULL,0x00); 

使用一次性位至少讓圖像渲染,但與黑色的其中alpha應的區域。

+0

以任何機會爲您的打印機PostScript打印機? Postscript對透明膠片的支持有限。 – 2013-03-01 23:52:59

+0

原來正在測試的打印機是PCL 6打印機。它在XPS文檔編寫器中也表現出相同的行爲(打印到文件)。 – 2013-03-05 13:24:41

+0

啊,那麼你可以不理我的答案。除非你發佈你的代碼,否則我不知道任何人都可以提供幫助。 – 2013-03-05 14:56:49

回答

2

好的,我想我在這裏找到了解決方案。那麼這並不能解釋爲什麼上面討論的方式不起作用,但它提供了一條前進的道路。我們的課都是基於ATL :: CImage的。看起來解決方案的真正關鍵在於ATL :: CImage在加載某些alpha圖像時會以某種方式影響圖像數據。例如,對於報告相同格式的圖像,它會反轉一種顏色其他或不顯示其中之一......這樣的事情。作爲測試,我將與讀入CImage :: Load中相同的數據存儲到Gdiplus :: Image實例中,並將其用於繪製到圖形實例(以下代碼)。這固定了所有的問題,所以在這一點上,故事的寓意就是用更新的東西替換基於ATL的代碼,因爲它不會對alpha圖片做正確的事情。

下面是最新的代碼:

int width = rectDest.right - rectDest.left; 
    int height = rectDest.bottom - rectDest.top; 

    Gdiplus::Graphics gfx(hDestDC); 
    //These next two lines allow resizing and printing of JPG to a printer 
    //without them GDI+ seems to have trouble resizing and repositioning 
    //JPEG files to fit onto the printer context and renders them off screen 
    //and distorted. 
    gfx.SetInterpolationMode(Gdiplus::InterpolationModeHighQuality); 
    gfx.SetPageUnit(Gdiplus::UnitPixel); 
    Gdiplus::Rect destination(rectDest.left, rectDest.top,width, height); 
    Gdiplus::ImageAttributes attributes; 
    //The color matrix has to be set onto the attributes or otherwise 
    //alpha will not work even though it's the identity. Also you 
    //can tweak the position at [4,4] to adjust alpha for the whole image 
    //and have per-pixel alpha as well. 
    Gdiplus::ColorMatrix matrix = {1.0, 0.0, 0.0, 0.0, 0.0, 
            0.0, 1.0, 0.0, 0.0, 0.0, 
            0.0, 0.0, 1.0, 0.0, 0.0, 
            0.0, 0.0, 0.0, 1.0, 0.0, 
            0.0, 0.0, 0.0, 0.0, 1.0}; 
    attributes.SetColorMatrix(&matrix,Gdiplus::ColorMatrixFlagsDefault, Gdiplus::ColorAdjustTypeBitmap); 
    gfx.DrawImage(gdiImage, destination, 0,0, GetWidth(),GetHeight(),Gdiplus::UnitPixel, &attributes, NULL, NULL); 
+0

ATL :: CImage來自GDI時代(在GDI +之前)。除了罕見的例外,GDI操作不使用甚至保留Alpha通道。所以這個解決方案很有意義 – 2013-03-05 20:37:00

1

測試它PCL打印機上。我希望你會發現它是打印機,而不是你的代碼。如果是這種情況,唯一的解決方案是將整個頁面渲染到單個位圖,然後將該位圖傳輸到打印機。這不是非常理想的性能,但它可以在所有打印機,Postscript或其他軟件上可靠運行。

如果您想了解更深入與後記和透明膠片的問題,維基百科有一個pretty good summary of the issue

+0

我會嘗試看看我是否可以在這裏找到PCL打印機。順便說一句......你的屏幕呈現出類似於我現在正在做的(更新後)接縫的想法,但只是一個圖像的基礎上,而不是整個屏幕,但有關該圖像數據的東西仍然與設備上下文有關。 – 2013-03-04 18:00:17

0

嘗試用白色填充第一目標區域,然後做混合。

您可能認爲它在屏幕上是正確的,因爲您碰巧混合到已被「擦除」而不透明白色像素的窗口上。

打印機可能試圖混合到未明確初始化的像素。也許打印機驅動程序假定這些像素最初是黑色的。這是一個合理的(如果違反直覺的)假設。打印紙爲白色這一事實導致人們認爲打印「透明」像素將使該區域變白,但從技術上講,這些像素未初始化。

+0

謝謝你的想法,我只是試過了,它似乎沒有幫助。 – 2013-03-05 13:23:26