1

空のビットマップがあり、TCanvasを受け取る描画ルーチンがあります。描画ルーチンはより大きなライブラリの一部であるため、事実上私の制御不能です。

簡単に言えば、描画ルーチンがピクセルに影響を与える場合は、ピクセルを不透明にします。触れられていない各ピクセルは透明のままにする必要があります。描画ルーチンで使用される色を制御できないため、このTransparentColorプロパティを使用する必要はありません。

これを達成する方法はありますか?キャンバスが描画先のピクセルのアルファレイヤーに影響を与えるように指定するために使用できるある種の設定はありますか?


更新:私はDelphi 2010を使用しています、そしてここに私が試したコードに従います:

Bmp := TBitmap.Create;
try
  Bmp.PixelFormat := pf32bit;
  Bmp.Transparent := False;
  Bmp.SetSize(Width, Height);

  // Ensure all pixels are black with opacity 0 (= fully transparent)
  ScanlineWidth := Width * SizeOf(TRGBQuad);
  for y := 0 to Bmp.Height - 1 do begin
    ZeroMemory(Bmp.ScanLine[y], ScanlineWidth);
  end;

  // call drawing routines here
  DrawContours(Bmp.Canvas, Width, Height);

  {$IFDEF DEBUG}
  Bmp.SaveToFile(OwnPath + 'Contours-' + IntToStr(GetTickCount) + '.bmp');
  {$ENDIF}

  Result := Bmp.ReleaseHandle;
finally
  Bmp.Free;
end;
4

3 に答える 3

1

私が正しく理解している場合
毎回完全に透明なビットマップを取得しています。

提案
関数を 書き直して、DrawContours描画するキャンバスの各領域にアルファ値を設定することができます。このルートをお勧めしますが、これらの関数を書き直したくないとどこかでおっしゃっていたと思います。

私が考えることができる他の唯一のオプションは、関数に渡した後(最初のbmpはすべて黒ですべて透明なので)、DrawContrours各ピクセルを検査し、黒でなくなった場合はアルファを255に変更することです。使用したくないと既に言った透明な色とプロパティを単に使用した場合と同じ結果になります。

考え
ビットマップを変更して、渡す描画ルーチンがルーチンの設計とは異なる方法で処理されるようにする方法がわかりません(また、1つでもあることに懐疑的です)。

最終回答
描画ルーチンを書き直すDrawControursか、使用しますTransparent color

于 2011-04-27T13:27:38.420 に答える
1

描画が高価でない場合は、次のアプローチがオプションになる可能性があります。透明なビットマップに1回、背景が白の1ビットビットマップに1回、背景が黒の1ビットビットマップに1回、合計3回描画して、アルファチャネルに加える必要のある変更を取得します(Timが正しいため-ビットマップは最初は完全に透明です。不透明にするピクセルを見つける必要があります)。

編集:最初のバージョンでは、背景が白の1ビットビットビットを1つだけ使用していました。残念ながら、これは明るい絵を検出しませんでした。それでは、さらに一歩進んで、2つの1ビットビットマップにします。ますます多くのビットマップがありますが、それは同様にエレガントさを失っています。

var
  Bmp: TBitmap;
  ScanlineWidth: Integer;
  x: Integer;
  y: Integer;
  // this one will track dark paintings
  BmpBitMaskWhite:TBitmap;
  // this one will track light paintings
  BmpBitMaskBlack:TBitmap;
  Row32bit, Row1bitWhite, Row1bitBlack:PByteArray;
  ByteAccess:Byte;

  // Init bitmaps needed for tracking pixels we need to change the alpha channel for
  procedure InitAlphaMaskBitmaps;
  begin
    BmpBitMaskWhite.PixelFormat:=pf1bit;          // <= one bit is enough
    BmpBitMaskWhite.Transparent:=False;
    BmpBitMaskWhite.SetSize(Width, Height);
    BmpBitMaskWhite.Canvas.Brush.Color:=clWhite;  // <= fill white; changes can then be seen as black pixels
    BmpBitMaskWhite.Canvas.FillRect(Rect(0,0,Width, Height));

    BmpBitMaskBlack.PixelFormat:=pf1bit;          // <= one bit is enough
    BmpBitMaskBlack.Transparent:=False;
    BmpBitMaskBlack.SetSize(Width, Height);
    BmpBitMaskBlack.Canvas.Brush.Color:=clBlack;  // <= fill black; changes can then be seen as white pixels
    BmpBitMaskBlack.Canvas.FillRect(Rect(0,0,Width, Height));
  end;

begin
  Bmp := TBitmap.Create;
  BmpBitMaskWhite:=TBitmap.Create;
  BmpBitMaskBlack:=TBitmap.Create;
  try
    Bmp.PixelFormat := pf32bit;
    Bmp.Transparent := False;
    Bmp.SetSize(Width, Height);

    InitAlphaMaskBitmaps;

    // ensure all pixels are black with opacity 0 (= fully transparent)
    ScanlineWidth := Width * SizeOf(TRGBQuad);
    for y := 0 to Bmp.Height - 1 do
    begin
      ZeroMemory(Bmp.ScanLine[y], ScanlineWidth);
    end;

    // call drawing routines here
    DrawContours(Bmp.Canvas, Width, Height);
    // call again to get areas where we need to un-transparent the Bmp (this is for dark paintings)
    DrawContours(BmpBitMaskWhite.Canvas, Width, Height);
    // call again to get areas where we need to un-transparent the Bmp  (this is for light paintings)
    DrawContours(BmpBitMaskBlack.Canvas, Width, Height);

    // modify alpha channel of Bmp by checking changed pixels of BmpBitMaskWhite and BmpBitMaskBlack
    // iterate all lines
    for y := 0 to Bmp.Height - 1 do
    begin
      // iterate all pixels
      for x := 0 to Bmp.Width - 1 do
      begin
        Row32bit:=PByteArray(Bmp.ScanLine[y]);
        Row1bitWhite:=PByteArray(BmpBitMaskWhite.ScanLine[y]);
        Row1bitBlack:=PByteArray(BmpBitMaskBlack.ScanLine[y]);

        // Now we need to find the changed bits in BmpBitMaskWhite and BmpBitMaskBlack to modify the corresponding
        // alpha-byte in Bmp. Black areas (Bit=0) in BmpBitMaskWhite are the ones that
        // have been drawn to, as well as white areas (Bit=1) in BmpBitMaskBlack.
        // Not pretty, but works.
        ByteAccess:=1 shl (7-x mod 8);
        if ((Row1bitWhite[x div 8] and ByteAccess)=0) or
           ((Row1bitBlack[x div 8] and ByteAccess)<>0) then
        begin
          Row32bit[x*4+3]:=255;
        end;
      end;
    end;

    {$IFDEF DEBUG}
    Bmp.SaveToFile('C:\Temp\Contours-' + IntToStr(GetTickCount) + '.bmp');
    BmpBitMaskWhite.SaveToFile('C:\Temp\Contours-' + IntToStr(GetTickCount) + '_BitMaskWhite.bmp');
    BmpBitMaskBlack.SaveToFile('C:\Temp\Contours-' + IntToStr(GetTickCount) + '_BitMaskBlack.bmp');
    {$ENDIF}

//    Result := Bmp.ReleaseHandle;
  finally
    Bmp.Free;
    BmpBitMaskWhite.Free;
    BmpBitMaskBlack.Free;
  end;

ちなみに、これらのビットマップの透明度を適切に示したプログラムはPixelFormerだけでした。その他(Gimp、IrfanView、Windows Faxthingy、FastStone Image Viewer、MS Paint)はすべて、透明な領域を黒に着色しました。

于 2011-04-27T14:58:26.340 に答える
0

いくつかのオプションをいじった後、私は次のものを機能させることができました:

  • ピクセル形式を32ビットに設定します。
  • に設定AlphaFormatafIgnoredます;
  • TransparentTrueに設定します。(これは重要です)
  • アルファ値をクリアします。
  • 描画ルーチンを呼び出します。
  • 次に、ビットマップをPNGに割り当て、それを保存します。

コード内:

Bmp := TBitmap.Create;
try
  Bmp.PixelFormat := pf32bit;
  Bmp.AlphaFormat := afIgnored;
  Bmp.Transparent := True;

  Bmp.SetSize(Width, Height);

  // Make bitmap fully transparent
  ScanlineWidth := Width * SizeOf(TRGBQuad);
  for y := 0 to Bmp.Height - 1 do begin
    ZeroMemory(Bmp.ScanLine[y], ScanlineWidth);
  end;

  DrawContours(Bmp.Canvas);

  PNG := TPNGImage.Create;
  try
    PNG.Assign(Bmp);
    PNG.SaveToFile('contours.png'); // => this one has the wanted transparency!
  finally
    PNG.Free;
  end;
finally
  Bmp.Free;
end;
于 2011-04-27T14:30:40.740 に答える