4

アルファ イメージをプリンター デバイス コンテキスト (リアルまたは XPS ドキュメント ライター) に印刷する際に問題が発生しています。画面のコンテキストと印刷プレビューではうまく機能しますが、ファイルまたはプリンターに印刷すると、別の画像の上に配置されると黒い四角として表示されます。以前は CImage::Draw を使用していましたが、GDI+ API を直接使用した場合と同様の結果 (黒または透明な四角) が得られました。

    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)

画像の性質も問題ではないようです。私が使用している2つの形式は次のとおりです。

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 データを使用して同じ結果をもたらします。画面上で行うのと同じように印刷コンテキストでアルファ画像を動作させる最良の方法は何ですか? アルファは BitmapMatrix を使用し、画像全体のブレンドを使用して機能するため、デバイスの機能が何かを誤って伝えている可能性はありますか?

編集: 2013 年 3 月 4 日

私の新しいアプローチは、すべてのアルファブレンディングをメモリ内で行うことです。プリンターがアルファブレンディングをサポートしていない場合は、ブレンドするメモリコンテキストを作成し、ブレンドされた結果をコンテキストにコピーするだけです。コードの重要な部分は次のようになります。

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

...驚いたことに、ほぼ同じ結果が得られました。実際には、すべてが正しく動作していることを確認するためだけに、画面の左側に沿って中間ステップをブリットしました。取得した背景とアルファ ブレンドの結果 (プリンター コンテキストにブリット) の両方が、画面上で見栄えがします。これはバグでしょうか?BitBlt は以前のブレンドのアルファ値をそのまま残していると思いますが、プリンター デバイス コンテキストをスローしているピクセル データの実際のアルファ値ですか? もしそうなら、どうすれば最終的な BitBlt の前にアルファを削除できますか?

編集:2013年3月5日
今、私は次のことを試しました:
1.デバイスに依存しないビットマップを使用してHBITMAP参照を作成します。
2. CreateDiscardableBitmap を使用して HBITMAP を作成します (最も成功しています)。
3. 各ピクセルのアルファ チャネルを手動で 0xFF と 0x00 に設定します。

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

使い捨てビットマップを使用すると、少なくとも画像がレンダリングされますが、アルファが必要な領域は黒になります。

4

3 に答える 3

2

わかりました、ここで解決策を見つけたと思います。上記の方法が機能しなかった理由を説明するものではありませんが、前に進む方法を提供します。私たちのクラスはすべて ATL::CImage に基づいていました。解決策の真の鍵は、ATL::CImage がこれらのアルファ画像の一部の画像データを読み込むときに何らかの形で誤って扱うことです。たとえば、同じ形式を報告した画像の場合、1 つの色を反転し、もう一方を表示しないか、このようなことを表示します。テストとして、CImage::Load に読み込まれた同じデータを Gdiplus::Image インスタンスに格納し、それを使用してグラフィック インスタンスに描画しました (以下のコード)。これによりすべての問題が修正されたため、この時点での話の教訓は、アルファ イメージでは正しいことを行わないため、ATL ベースのコードを新しいものに置き換えることであると思われます。

最新のコードは次のとおりです。

   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);
于 2013-03-05T19:06:01.063 に答える
1

PCL プリンターでテストします。コードではなく、プリンターであることがわかると思います。その場合、唯一の解決策は、ページ全体を 1 つのビットマップにレンダリングし、そのビットマップをプリンターにブリットすることです。パフォーマンス的にはあまり望ましいものではありませんが、すべてのプリンタ、Postscript などで確実に動作します。

Postscript と透明度の問題をより深く理解したい場合は、ウィキペディアに問題のかなり良い要約があります。

于 2013-03-04T15:52:21.010 に答える
0

最初にターゲット領域を白で塗りつぶしてから、ブレンドを実行してみてください。

不透明な白いピクセルの間に「消去」されたウィンドウにたまたまブレンドしているため、画面上で正しいと思う可能性があります。

プリンタが、明示的に初期化されていないピクセルにブレンドしようとしている可能性があります。おそらく、プリンタドライバは、これらのピクセルが最初は黒であると想定しています。これは合理的な(直感に反する場合)仮定です。プリンタ用紙が白であるという事実は、「透明な」ピクセルを印刷するとその領域が白のままになると推測することにつながりますが、技術的には、これらのピクセルは初期化されていません。

于 2013-03-04T22:14:17.720 に答える