2011-02-05 4 views
3

이 질문은 이전 질문에서 나왔습니다. 대부분의 코드는 Delphi의 이후 버전에서 잘 작동하는 제안 된 답변으로부터 왔습니다. D2006에서는 불투명도의 전체 범위를 얻지 못했고 이미지의 투명한 부분은 흰색으로 표시됩니다.왜이 D2006 코드가 PNG 이미지를 흐리게 표시하지 않습니까?

이미지는 http://upload.wikimedia.org/wikipedia/commons/6/61/Icon_attention_s.png입니다.
DFM을 저장 한 후에도 이미지가 그대로 유지되지 않으므로 런타임시 PNGImageCollection에서 런타임시 TImage로로드됩니다. 이 동작을 설명하기 위해 PNGImageCollection이 필요하지 않으며 디자인 타임에 PNG 이미지를 TImage로로드 한 다음 IDE에서 실행할 수 있습니다.

양식에 네 개의 단추가 있습니다. 각 단추는 불투명도의 다른 값을 설정합니다. 불투명도 = 0은 잘 작동합니다 (페인트 상자 이미지는 표시되지 않음, 불투명도 = 16은 흰색 배경을 제외하고는 괜찮음), 불투명도 = 64, 255는 비슷합니다. 불투명도는 약 10 %로 포화 상태 인 것으로 보입니다. 까지?

unit Unit18; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ExtCtrls, pngimage, StdCtrls, Spin, PngImageList; 

type 
    TAlphaBlendForm = class(TForm) 
    PaintBox1: TPaintBox; 
    Image1: TImage; 
    PngImageCollection1: TPngImageCollection; 
    Button1: TButton; 
    Button2: TButton; 
    Button3: TButton; 
    Button4: TButton; 
    procedure PaintBox1Paint(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    procedure Button3Click(Sender: TObject); 
    procedure Button4Click(Sender: TObject); 
    private 
    FOpacity : Integer ; 
    FBitmap : TBitmap ; 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    AlphaBlendForm: TAlphaBlendForm; 

implementation 

{$R *.dfm} 

procedure TAlphaBlendForm.Button1Click(Sender: TObject); 
begin 
FOpacity:= 0 ; 
PaintBox1.Invalidate; 
end; 

procedure TAlphaBlendForm.Button2Click(Sender: TObject); 
begin 
FOpacity:= 16 ; 
PaintBox1.Invalidate; 
end; 

procedure TAlphaBlendForm.Button3Click(Sender: TObject); 
begin 
FOpacity:= 64 ; 
PaintBox1.Invalidate; 
end; 

procedure TAlphaBlendForm.Button4Click(Sender: TObject); 
begin 
FOpacity:= 255 ; 
PaintBox1.Invalidate; 
end; 

procedure TAlphaBlendForm.FormCreate(Sender: TObject); 
begin 
    Image1.Picture.Assign (PngImageCollection1.Items [0].PNGImage) ; 
    FBitmap := TBitmap.Create; 
    FBitmap.Assign(Image1.Picture.Graphic);//Image1 contains a transparent PNG 
    FBitmap.PixelFormat := pf32bit ; 
    PaintBox1.Width := FBitmap.Width; 
    PaintBox1.Height := FBitmap.Height; 
end; 

procedure TAlphaBlendForm.PaintBox1Paint(Sender: TObject); 

var 
    fn: TBlendFunction; 
begin 
    fn.BlendOp := AC_SRC_OVER; 
    fn.BlendFlags := 0; 
    fn.SourceConstantAlpha := FOpacity; 
    fn.AlphaFormat := AC_SRC_ALPHA; 
    Windows.AlphaBlend(
    PaintBox1.Canvas.Handle, 
    0, 
    0, 
    PaintBox1.Width, 
    PaintBox1.Height, 
    FBitmap.Canvas.Handle, 
    0, 
    0, 
    FBitmap.Width, 
    FBitmap.Height, 
    fn 
); 
end; 

end. 

** (graphics32 TImage32 사용)이 코드는 거의 **

unit Unit18; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, ExtCtrls, pngimage, StdCtrls, Spin, PngImageList, GR32_Image; 

type 
    TAlphaBlendForm = class(TForm) 
    Button1: TButton; 
    Button2: TButton; 
    Button3: TButton; 
    Button4: TButton; 
    Image321: TImage32; 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    procedure Button3Click(Sender: TObject); 
    procedure Button4Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    AlphaBlendForm: TAlphaBlendForm; 

implementation 

{$R *.dfm} 

procedure TAlphaBlendForm.Button1Click(Sender: TObject); 
begin 
Image321.Bitmap.MasterAlpha := 0 ; 
end; 

procedure TAlphaBlendForm.Button2Click(Sender: TObject); 
begin 
Image321.Bitmap.MasterAlpha := 16 ; 
end; 

procedure TAlphaBlendForm.Button3Click(Sender: TObject); 
begin 
Image321.Bitmap.MasterAlpha := 64 ; 
end; 

procedure TAlphaBlendForm.Button4Click(Sender: TObject); 
begin 
Image321.Bitmap.MasterAlpha := 255 ; 
end; 

end. 

** (UPDATE) (graphics32 TImage32 사용)이 코드가하는 일 ** 작동

다음 코드는 런타임에 PNG 이미지를 Graphics32.TIMage32에 할당하는 데 성공합니다. 알파 채널이있는 PNG 이미지는 디자인 타임에 TPNGImageCollection (실제로 유용한 구성 요소로 임의 크기의 이미지를 혼합 할 수 있도록)에로드됩니다. 양식을 만들면 스트림에 기록 된 다음 LoadPNGintoBitmap32을 사용하여 스트림에서 Image32로 읽습니다. 이 작업이 끝나면 TImage32.Bitmap.MasterAlpha에 할당하여 불투명도를 제어 할 수 있습니다. OnPaint 처리기로 귀찮게하지 않아도됩니다.

+0

내가 투명성이 TBitmap.Assign에 대한 호출에 손실됩니다 생각합니다. Windows API 함수 직접 조작이 포함됩니다이 수정하는 방법을 찾고 있어요. D6 사본을 사용하고 있습니다. –

+0

실제로 D6에서 Gustavo Daud의 PNG 단위를 사용하는 코드에서 투명도가 PNG 수준에서 올바르게 처리되고 있다고 생각하지 않습니다. 나는 그들이 올바르게 작동 할 것이므로 부분 투명도를 가진 .ico 파일을 사용하여 다른 압정을 시도 할 것입니다! –

+0

OK, 포기합니다. Graphics.pas는 Delphi의 이러한 오래된 버전이 부분 투명도 및 알파 채널을 제대로 지원한다는 것을 믿지 않습니다.이러한 도구로이 작업을하려면 낮은 수준의 Win API 작업을 많이해야합니다. PNG 이미지 단위는 내가 말할 수있는 한 부분 투명도를 지원하지 않습니다. XE로 이동할 때라고 생각합니다! –

답변

5

데이빗이 질문에 댓글을 달았을 때 그래픽을 비트 맵에 할당하면 알파 채널 정보가 손실됩니다. 따라서 할당 후 픽셀 형식을 pf32bit으로 설정하는 데 아무런 의미가 없습니다. AlphaBlend 호출이 실패하는 것을 제외하고 비트 맵에 픽셀 당 알파가 없습니다.

그러나 png 개체는 투명도 정보를 고려하여 캔버스에서 그리는 방법을 알고 있습니다. 따라서 그래픽을 할당하는 대신 비트 맵 캔버스에서 그리기를 수행 한 다음 알파 채널이 없으므로 BLENDFUNCTION에서 AC_SRC_ALPHA 플래그를 제거하십시오.

procedure TAlphaBlendForm.FormCreate(Sender: TObject); 
begin 
    Image1.Picture.LoadFromFile(
     ExtractFilePath(Application.ExeName) + 'Icon_attention_s.png'); 

    FBitmap := TBitmap.Create; 
    FBitmap.Width := Image1.Picture.Graphic.Width; 
    FBitmap.Height := Image1.Picture.Graphic.Height; 

    FBitmap.Canvas.Brush.Color := Color;  // background color for the image 
    FBitmap.Canvas.FillRect(FBitmap.Canvas.ClipRect); 

    FBitmap.Canvas.Draw(0, 0, Image1.Picture.Graphic); 

    PaintBox1.Width := FBitmap.Width; 
    PaintBox1.Height := FBitmap.Height; 
end; 

procedure TAlphaBlendForm.PaintBox1Paint(Sender: TObject); 
var 
    fn: TBlendFunction; 
begin 
    fn.BlendOp := AC_SRC_OVER; 
    fn.BlendFlags := 0; 
    fn.SourceConstantAlpha := FOpacity; 
    fn.AlphaFormat := 0; 
    Windows.AlphaBlend(
    PaintBox1.Canvas.Handle, 
    0, 
    0, 
    PaintBox1.Width, 
    PaintBox1.Height, 
    FBitmap.Canvas.Handle, 
    0, 
    0, 
    FBitmap.Width, 
    FBitmap.Height, 
    fn 
); 
end; 

를하거나 중간 TImage를 사용하지 않고 : : 아래

는 D2007 여기에 코드를 작동하고

procedure TAlphaBlendForm.FormCreate(Sender: TObject); 
var 
    PNG: TPNGObject; 
begin 
    PNG := TPNGObject.Create; 
    try 
    PNG.LoadFromFile(ExtractFilePath(Application.ExeName) + 'Icon_attention_s.png'); 

    FBitmap := TBitmap.Create; 
    FBitmap.Width := PNG.Width; 
    FBitmap.Height := PNG.Height; 

    FBitmap.Canvas.Brush.Color := Color; 
    FBitmap.Canvas.FillRect(FBitmap.Canvas.ClipRect); 

    PNG.Draw(FBitmap.Canvas, FBitmap.Canvas.ClipRect); 

    PaintBox1.Width := FBitmap.Width; 
    PaintBox1.Height := FBitmap.Height; 
    finally 
    PNG.Free; 
    end; 
end; 
+0

+1 니스. 구 델파이 용 PNG 코드는 부분 투명도를 지원하지 않으므로 애비뉴가 파멸되었습니다. 필자는 CodeGear가이 코드를 인수 할 때 수행 한 작업에 대해 정말로 싫어합니다. 이전 버전의 사용자를 거부하려고 시도하자 PNG를 사용할 수있는 능력이 최악이었습니다. –

+0

@Sertac, @ David 감사합니다. 나는 내일 D2006 (3am here!)의 아래에서 그것을 시험 할 것이다. 그동안 나는 TImage32를 사용하여 작업하는 것처럼 보이지만, 디자인 타임에 PNG를 TImage32에로드 할 때 알파 채널을 사용할 수 없다는 점을 제외하고는 질문을 편집했습니다. 이미지의 배경은 검정색이나 투명하지 않습니다. . 같은 이미지를 apha 채널에로드하여 작동하도록 정렬 할 수 있지만 이미지의 삼각형 부분이 100 % 불투명도가 될 수 있도록 이미지에서 마스크를 만들어야합니다. 이 문제를 자동으로 어떻게 처리 할 수 ​​있습니까? – rossmcm

+1

@user는 디자인 타임에로드를 포기합니다. 리소스를 사용하고 런타임에 수행하십시오. –