흐르는 시간의 블로그...

나도 저 문제에 봉착 했다.

델파이가 아니고 C++ Builder 지만...

어쨋든 두 툴이 거의 동일하다시피 하기 때문에...

앞에서 거론한 문제를 풀기위해

첫번째로 TGraphicControl의 Text를 반투명 혹은 투명하게 처리하기 위한 방안이다.

저 답을 보고 싶었으나, "돈내고 가입"해야 보는 곳이었다.

어쨋든 결재는 했으니.. 한번 해보자 ㅡㅡ;;;

-----------------------------------------------------------------------------------------------------------

첫번째 답

-------------

You need to calculate font color before painting on canvas.

Canvas.Font.Color := BlendColors(clBtnFace, clWindowText, 50);

function BlendColors(Color1, Color2: TColor; Opacity: Byte): TColor;
var
  r, g, b: Byte;
  c1, c2: PByteArray;
begin
  Color1 := ColorToRGB(Color1);
  Color2 := ColorToRGB(Color2);
  c1 := @Color1;
  c2 := @Color2;

  r := Trunc(c1[0] + (c2[0] - c1[0]) * Opacity / 256);
  g := Trunc(c1[1] + (c2[1] - c1[1]) * Opacity / 256);
  b := Trunc(c1[2] + (c2[2] - c1[2]) * Opacity / 256);

  Result := RGB(r, g, b);
end;

-----------------------------------------------------------------------------------------------------------

두번째 답

------------------

There are several ways how to do this.. Here's one of them:

object Image1: TImage
  Left = 2
  Top = 34
  Width = 317
  Height = 269
  OnMouseDown = Image1MouseDown
 OnMouseMove = Image1MouseMove
end

object Edit1: TEdit
  Left = 32
  Top = 0
  Width = 185
  Height = 21
  TabOrder = 0
  Text = 'Some different text'
end

object Label1: TLabel
  Left = 0
  Top = 4
  Width = 21
  Height = 13
  Caption = 'Text'
end

object Edit2: TEdit
  Left = 264
  Top = 0
  Width = 57
  Height = 21
  TabOrder = 1
  Text = '127'
end

object Label2: TLabel
  Left = 232
  Top = 4
  Width = 27
  Height = 13
  Caption = 'Blend'
end

object Bevel1: TBevel
  Left = 0
  Top = 32
  Width = 321
  Height = 273
end


unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Image1: TImage; Edit1: TEdit; Label1: TLabel; Edit2: TEdit; Label2: TLabel; Bevel1: TBevel; procedure Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure FormCreate(Sender: TObject); procedure TranspTxt(s : string; x, y : cardinal; BorderX, BorderY : byte; transp : byte); end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin with Image1, Picture.Bitmap do begin Stretch := true; Width := Image1.Width; Height := Image1.Height; PixelFormat := pf24bit; end; end; procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin with Image1.Canvas do case Button of mbLeft : MoveTo(x, y); mbRight : TranspTxt(Edit1.Text, x, y, 4, 0, StrToInt(Edit2.Text)); end; end; procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if ssLeft in Shift then begin Image1.Canvas.LineTo(x, y); end; end; procedure TForm1.TranspTxt(s : string; x, y : cardinal; BorderX, BorderY : byte; transp : byte); // transp : // 0 - no transparency // 255 - full transparency (invisible) type TLine = array [0..32767] of TRGBTriple; PLine = ^TLine; var bmp : TBitmap; l1, l2 : PLine; w, h : word; n1, n2 : single; begin bmp := TBitmap.Create; with bmp do begin PixelFormat := Image1.Picture.Bitmap.PixelFormat; with Canvas do begin with Font do begin // font params - name, size, style, color, charset etc Name := 'Courier New'; Size := 14; Style := []; Color := $0000ff; // red end; Width := TextWidth (s) + BorderX * 2; // calculate width of text frame Height := TextHeight(s) + BorderY * 2; // calculate height of text frame Pen.Width := 3; // set border width Pen.Color := $000000; // color Brush.Color := $ffffff; // background color Rectangle(ClipRect); // draw frame (background & border) Brush.Style := bsClear; TextOut(BorderX, BorderY, s); // draw text end; n1 := 1 / 255 * transp; n2 := 1 - n1; for h := 0 to Height - 1 do begin // put it on Image1.Picture.Bitmap if y + h >= Image1.Picture.Bitmap.Height then break; // bottom of the image l1 := Image1.Picture.Bitmap.ScanLine[y + h]; l2 := ScanLine[h]; for w := 0 to Width - 1 do begin if x + w > Image1.Picture.Bitmap.Width then break; // right margin of the image l1[x + w].rgbtRed := Trunc(l1[x + w].rgbtRed * n1 + l2[w].rgbtRed * n2); l1[x + w].rgbtGreen := Trunc(l1[x + w].rgbtGreen * n1 + l2[w].rgbtGreen * n2); l1[x + w].rgbtBlue := Trunc(l1[x + w].rgbtBlue * n1 + l2[w].rgbtBlue * n2); end; end; end; bmp.Free; Image1.Refresh; end; end.


-----------------------------------------------------------------------------------------------------------

세번째답

--------------

Create an in-memory bitmap.
Use TextOut to write your to the bitmap
Use AlphaBlend to merge the new bitmap and your destination with your required transparency (trans, 0 to 255)

***Note: AlphaBlend does not work on all systems. The application must be running under Windows 2000 or better***

eg ...

procedure TForm1.AlphaTextOut(dest : TCanvas ; x, y: integer; s: string; trans: byte);
var
  MyBMP : TBitmap;
  BlendFunction : TBlendFunction;
  ASize : TSize;
begin
  try
    MyBMP := TBitmap.create;
    GetTextExtentPoint32(MyBMP.Canvas.Handle,PCHAR(s),length(s),ASize);
    MyBMP.Width := MyBMP.Canvas.TextWidth(s);
    MyBMP.Height := MyBMP.Canvas.TextHeight(s);
    MyBMP.Canvas.TextOut(0,0,s);
  
  with BlendFunction do
  begin
    BlendOp := AC_SRC_OVER;
    BlendFlags := 0;
    SourceConstantAlpha := trans;
    AlphaFormat := 0;
  end;


  windows.AlphaBlend(
    Dest.Handle, // handle to destination DC
    x, // x-coord of upper-left corner
    y, // y-coord of upper-left corner
    MyBMP.Width, // width of destination rectangle
    MyBMP.Height, // height of destination rectangle
    MyBMP.Canvas.Handle, // handle to source DC
    0, // x-coord of source upper-left corner
    0, // y-coord of source upper-left corner
    MyBMP.Width, // width of source rectangle
    MyBMP.Height, // height of source rectangle
    blendFunction // alpha-blending function
  );
  finally
    MyBMP.free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  AlphaTextOut(image1.picture.bitmap.canvas ,0 ,0, 'A test string' ,200)
end;
--------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------

선택된 답

--------

hello yarek, here is my version that is specifically for a TPanel, instead of a bitmap. . . It is called - procedure BlendTextOut
the first parameter is for the Panel you want the text to go onto, the X and Y are position, and the Text parameter is the String to be drawn on the panel, the PerCentShow is a number from 1 to 99 for the percent of transparency to show the text, I left out the zero and 100 percent, since they make no sence for a blend text. . .


type
  TPerCent = 1..99;

procedure BlendTextOut(aPanel: TPanel; X, Y: Integer; const Text: String; PerCentShow: TPerCent);
type
  PColor32 = ^TColor32;
  TColor32 = packed record
  b, g, r, a: Byte;
end;
var
  BmpText, panelBmp: TBitmap;
  DCp: HDC;
  xx, yy, ColorBk, wid: Cardinal;
  pClPanel, pClBmp: PColor32;
  AmSh, AmBk: Single;
begin
  if not Assigned(aPanel) then Exit;
  if (X > aPanel.Width-1) or (Y > aPanel.Height -1) then Exit;
  
  BmpText := TBitmap.Create;
  with BmpText, BmpText.Canvas do
  begin
    PixelFormat := pf32Bit;
    wid := ColorToRGB(aPanel.Color);
    Brush.Color := wid;
    Font.Assign(aPanel.Font);
    Width := TextWidth(Text);
    Height := TextHeight(Text);
    if (X < -Width) or (Y < -Height) then
    begin
      FreeAndNil(BmpText);
      Exit;
    end;

    Brush.Style := bsClear;
    TextOut(0, 0, Text);

    panelBmp := TBitmap.Create;
    panelBmp.PixelFormat := pf32Bit;
    panelBmp.Width := Width;
    panelBmp.Height := Height;
  end;

  DCp := GetDC(aPanel.Handle);
  BitBlt(panelBmp.Canvas.Handle,0,0, panelBmp.width, panelBmp.Height, DCp, X,Y, SRCCOPY);
  ReleaseDC(aPanel.Handle,DCp);
  ColorBk := wid;
  TColor32(ColorBk).r := TColor32(wid).b;
  TColor32(ColorBk).b := TColor32(wid).r;
  // ColorBk := ((wid and $FF) shl 16) or (wid and $FF00) or
  // ((wid and $FF0000) shr 16);

  AmSh := PerCentShow / 100;
  AmBk := 1.0 - AmSh;
  wid := Pred(BmpText.Width);
  pClPanel := panelBmp.ScanLine[panelBmp.Height - 1];
  pClBmp := BmpText.ScanLine[BmpText.Height - 1];
  
  for yy := BmpText.Height - 1 downto 0 do
  begin
    for xx := 0 to wid do
    begin
      if PDWORD(pClBmp)^ <> ColorBk then
      begin
        pClPanel.b := Round((pClBmp.b * AmSh) + (pClPanel.b * AmBk));
        pClPanel.g := Round((pClBmp.g * AmSh) + (pClPanel.g * AmBk));
        pClPanel.r := Round((pClBmp.r * AmSh) + (pClPanel.r * AmBk));
      end;

      Inc(pClPanel);
      Inc(pClBmp);
    end;
  end;

  FreeAndNil(BmpText);
  DCp := GetDC(aPanel.Handle);
  BitBlt(DCp,x,y, panelBmp.width, panelBmp.Height, panelBmp.Canvas.Handle, 0,0, SRCCOPY);
  ReleaseDC(aPanel.Handle,DCp);
  FreeAndNil(panelBmp);
end;


나도 저 문제에 봉착 했다.

델파이가 아니고 C++ Builder 지만...

어쨋든 두 툴이 거의 동일하다시피 하기 때문에...

지금의 문제는 TGraphicControl인 경우 배경을 투명하게 하는 것이 브러쉬만 바꿔주면 된다.

Canvas->Brush->Style = bsClear;

그러나 이 경우 Alpla를 적용할 방법이 없다.

투명도 조절이 불가능하다.

투명도를 조절하는 방법으로는 windows 2000이후에 나오는

SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle, 0, (255 * 70) / 100, LWA_ALPHA);

위의 두코드를 사용하면 되나 저 경우 윈도우 핸들이 있어야 한다.

따라서 윈도우 핸들이 있는 TCustomControl을 상속 받아 사용하는 방법이 있다.

이 경우 배경을 투명하게 하기 위한 처리를 해야 한다.

void __fastcall TDSMText::CreateParams(TCreateParams &Params)
{
TCustomControl::CreateParams(Params);
Params.ExStyle = Params.ExStyle | WS_EX_TRANSPARENT;
}

위와 같은 방법으로 윈도우 전체를 투명하게 한다.

void __fastcall TRectTracker::WMEraseBkgnd(Messages::TWMMouse &Message)
{
Message.Result = false;
}

위의 코드도 추가한다.

그러나, Tracker에서 배경이 희게 그려지는 현상이 발생하면서 다시 원점으로 갔다.

둘 중 하나를 선택한다면 TGraphicControl을 쓰고 싶다.

윈도우를 받아서 쓰는 부분은 정말 많은 문제가 발생하기 때문이다.

...

알파 블랜드로 한번 해보자 ㅠ.ㅠ

------------------------------------------------------------------------------------------

GDI 에선 AlphaBlend 라는 함수로 가능하기는 하는데

찍을 부분의 이미지 색상과 혼합을 해야 제대로 구현이 됩니다

계산식이야 MSDN 에도 있고 여기 Q&A 에 검색해도 있습니다.

AlphaBlend 로 하다가 계산하는거 짜증나서

GDI+ 찾아 보니까 있더군여..

MSDN 에서 발췌했습니다.

여기 검색해봐도 없길래... 갖다 붙여 넣습니다... 참고하세요..


Using a Color Matrix to Set Alpha Values in Images

The Bitmap class (which inherits from the Image class) and the ImageAttributes class provide functionality for getting and setting pixel values. You can use the ImageAttributes class to modify the alpha values for an entire image, or you can call the SetPixel method of the Bitmap class to modify individual pixel values. For more information on setting individual pixel values, see Setting the Alpha Values of Individual Pixels.

The following example draws a wide black line and then displays an opaque image that covers part of that line.

Bitmap bitmap(L"Texture1.jpg");
Pen pen(Color(255, 0, 0, 0), 25);

// First draw a wide black line.
graphics.DrawLine(&pen, Point(10, 35), Point(200, 35));

// Now draw an image that covers part of the black line.
graphics.DrawImage(&bitmap,
Rect(30, 0, bitmap.GetWidth(), bitmap.GetHeight()));

The following illustration shows the resulting image, which is drawn at (30, 0). Note that the wide black line doesn't show through the image.

The ImageAtributes class has many properties that you can use to modify images during rendering. In the following example, an ImageAttributes object is used to set all the alpha values to 80 percent of what they were. This is done by initializing a color matrix and setting the alpha scaling value in the matrix to 0.8. The address of the color matrix is passed to the SetColorMatrix method of the ImageAttributes object, and the address of the ImageAttributes object is passed to the DrawImage method of a Graphics object.

// 다음 코드가 반투명 효과를 일으키게하는 소스이며.. 주석과 같이 4행4열의 0.8값을 주의깊게 보십시요

// 이 값을 바꿔주면서 이미지를 확인해 보시면 잘 알수 있을겁니다...

// 그럼.. 참고하세요..

// Create a Bitmap object and load it with the texture image.
Bitmap bitmap(L"Texture1.jpg");
Pen pen(Color(255, 0, 0, 0), 25);

// Initialize the color matrix.
// Notice the value 0.8 in row 4, column 4.
ColorMatrix colorMatrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.8f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

// Create an ImageAttributes object and set its color matrix.
ImageAttributes imageAtt;
imageAtt.SetColorMatrix(&colorMatrix, ColorMatrixFlagsDefault,
ColorAdjustTypeBitmap);

// First draw a wide black line.
graphics.DrawLine(&pen, Point(10, 35), Point(200, 35));

// Now draw the semitransparent bitmap image.
INT iWidth = bitmap.GetWidth();
INT iHeight = bitmap.GetHeight();
graphics.DrawImage(
&bitmap,
Rect(30, 0, iWidth, iHeight), // Destination rectangle
0, // Source rectangle X
0, // Source rectangle Y
iWidth, // Source rectangle width
iHeight, // Source rectangle height
UnitPixel,
&imageAtt);

During rendering, the alpha values in the bitmap are converted to 80 percent of what they were. This results in an image that is blended with the background. As the following illustration shows, the bitmap image looks transparent; you can see the solid black line through it.

Where the image is over the white portion of the background, the image has been blended with the color white. Where the image crosses the black line, the image is blended with the color black.

원본은 트랙백을 쫓아가세요~~~

TGraphicControl을 반투명하게 만들어야 하는데...

원하는건 안나오고 계속 윈도 투명만들기 놀이만 나오네.. ㅠ.ㅠ

------------------------------------------------------------------------------------

[질문]

전에.. 윈도우를 만들때 RGB 를 섞어서.. 어떻게 만드는 걸 찾아서 해봤었거든요.
근데 그걸 날려먹어서리.. 다시 인터넷에 찾아볼려구 해두 안보이네요 ㅡ_ㅡ;;
좋은 하루 되시길~~~

[답변 - 금호창님이 답변하신글]

// 헤더파일에..여러 상수 지정. 옵션을 바꿀 수도 있슴.

#define WS_EX_LAYERED 0x00080000
#define LWA_COLORKEY 0x00000001
#define LWA_ALPHA 0x00000002
#define ULW_COLORKEY 0x00000001
#define ULW_ALPHA 0x00000002
#define ULW_OPAQUE 0x00000004

typedef BOOL(WINAPI *SLWA)(HWND, COLORREF, BYTE, DWORD); // 요거 선언해주고...

// 반투명하게 만드는 루틴.
SLWA pSetLayeredWindowAttributes = NULL; // 함수포인터 선언, 초기화.
HINSTANCE hmodUSER32 = LoadLibrary("USER32.DLL"); // 인스턴스 얻음.
pSetLayeredWindowAttributes=(SLWA)GetProcAddress(hmodUSER32,"SetLayeredWindowAttributes");
// 함수포인터 얻음.
HWND hwnd = this->m_hWnd; // 다이얼로그의 핸들 얻음.
SetWindowLong(hwnd, GWL_EXSTYLE,
GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
// pSetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);
pSetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_ALPHA);
// pSetLayeredWindowAttributes(hwnd, 0, (255 * 70) / 100, LWA_COLORKEY);
// 다이얼로그 반투명하게 만듬.