Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Полупрозрачное изображение


Автор: Gigabyte 12.4.2006, 12:50
как скопировать одно изображение на другое с прозрачностью 50%

Автор: Alexeis 12.4.2006, 13:02
Gigabyte, у меня большие сомнения что это можно сделать стандартными средствами, но математику ни кто не отменял smile
примерно так:
Код

 Canvas1.pixels[i, j] := (Canvas1.pixels[i, j] + Canvas2.pixels[i, j]) div 2;


хотя получится это наверное плохо, вообщем нашел следующий пример
Код

function MixBytes(FG, BG, TRANS: byte): byte;
 asm
  push bx  // push some regs
  push cx
  push dx
  mov DH,TRANS // remembering Transparency value (or Opacity - as you like)
  mov BL,FG    // filling registers with our values
  mov AL,DH    // BL = ForeGround (FG)
  mov CL,BG    // CL = BackGround (BG)
  xor AH,AH    // Clear High-order parts of regs
  xor BH,BH
  xor CH,CH
  mul BL       // AL=AL*BL
  mov BX,AX    // BX=AX
  xor AH,AH
  mov AL,DH
  xor AL,$FF   // AX=(255-TRANS)
  mul CL       // AL=AL*CL
  add AX,BX    // AX=AX+BX
  shr AX,8     // Fine! Here we have mixed value in AL
  pop dx       // Hm... No rubbish after us, ok?
  pop cx
  pop bx       // Bye, dear Assembler - we go home to Delphi!
end;

 // Here we mix R,G and B channels of our colors separately.
// The value of T is between 0 and 255 as described above.

// As you know, TColor value is 4 bytes length integer value where
// low byte is red channel, 2nd byte is green and 3rd byte is blue

function MixColors(FG, BG: TColor; T: byte): TColor;
 var r,g,b:byte;
 begin
   R := MixBytes(FG and 255,BG and 255,T); // extracting and mixing Red
  G := MixBytes((FG shr 8) and 255,(BG shr 8) and 255,T); // the same with green
  B := MixBytes((FG shr 16) and 255,(BG shr 16) and 255,T); // and blue, of course
  Result := r+g*256+b*65536; // finishing with combining all channels together
end;


Автор: Alexeis 12.4.2006, 13:26
Поясняю код TRANS - определяет прозрачность исходного изображения
(255 - trans) - прозрачность фона - в нашем случае они равны и ,следовательно, этот код при TRANS=128 (50%) будет делать тоже что и мойsmile.

Автор: Snowy 12.4.2006, 19:37
В Win98 и старше имеется функция AlphaBlend.
И ничего не нужно изобретать - прозрачность рисует любую - от 0 до 255.

Автор: Alexeis 13.4.2006, 09:25
Snowy, случайно нет примера, а то в документации не совсем ясно описан последний параметр
Цитата

NDFUNCTION blendFunction  // alpha-blending function

Автор: Snowy 13.4.2006, 10:21
Код
procedure TForm1.Button1Click(Sender: TObject);
var
  bmp1, bmp2: TBitMap;
  Blend: TBlendFunction;
begin
  bmp1 := TBitMap.Create;
  bmp2 := TBitMap.Create;
  bmp1.LoadFromFile('C:\1.bmp'); // загружаем 1 битмап
  bmp2.LoadFromFile('C:\2.bmp'); // и второй битмап
  bmp1.PixelFormat := pf32bit; // переводим оба в 32 бит
  bmp2.PixelFormat := pf32bit;
  Blend.BlendOp := AC_SRC_OVER;
  Blend.BlendFlags := 0;
  Blend.SourceConstantAlpha := 128; // прозрачность 50% (0 - 255)
  Blend.AlphaFormat := AC_SRC_ALPHA;
  // накладываем битмап 2 на битмап 1
  if Windows.AlphaBlend(bmp1.Canvas.Handle, 0, 0, bmp1.Width, bmp1.Height,
                        bmp2.Canvas.Handle, 0, 0, bmp2.Width, bmp2.Height, Blend) then
    Canvas.Draw(0, 0, bmp1) // рисуем результат на форме
  else ShowMessage(IntToStr(GetLastError)); // или код ошибки, если наложить не удалось
  bmp1.Free; bmp2.Free; // уничтожаем битмапы
end;

Автор: Alexeis 13.4.2006, 10:48
Snowy, а если после

Код

  bmp1.PixelFormat := pf32bit; // переводим оба в 32 бит    
  bmp2.PixelFormat := pf32bit;


поменять "цвет "альфа канала у отдельных писелей или областей, то как это скажется на результирующем изображении при такой отрисовке??

Автор: Snowy 13.4.2006, 10:56
Меняй как хочешь.
Единственное требование - битмап должен быть 32 бита.

Цитата(alexeis1 @ 13.4.2006, 10:48 Найти цитируемый пост)
то как это скажется на результирующем изображении при такой отрисовке??
Вот правило, по которому смешиваются каналы:
Цитата
If the source bitmap has no per-pixel alpha value (that is, AC_SRC_ALPHA is not set), the SourceConstantAlpha value determines the blend of the source and destination bitmaps, as shown in the following table. Note that SCA is used for SourceConstantAlpha here. Also, SCA is divided by 255 because it has a value that ranges from 0 to 255.

Dst.Red = Src.Red * (SCA/255.0) + Dst.Red * (1.0 - (SCA/255.0))
Dst.Green = Src.Green * (SCA/255.0) + Dst.Green * (1.0 - (SCA/255.0))
Dst.Blue = Src.Blue * (SCA/255.0) + Dst.Blue * (1.0 - (SCA/255.0))

If the destination bitmap has an alpha channel, then the blend is as follows.

Dst.Alpha = Src.Alpha * (SCA/255.0) + Dst.Alpha * (1.0 - (SCA/255.0))

If the source bitmap does not use SourceConstantAlpha (that is, it equals 0xFF), the per-pixel alpha determines the blend of the source and destination bitmaps, as shown in the following table.

Dst.Red = Src.Red + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue

If the destination bitmap has an alpha channel, then the blend is as follows.

Dest.alpha = Src.Alpha + (1 - SrcAlpha) * Dst.Alpha

If the source has both the SourceConstantAlpha (that is, it is not 0xFF) and per-pixel alpha, the source is pre-multiplied by the SourceConstantAlpha and then the blend is based on the per-pixel alpha. The following tables show this. Note that SourceConstantAlpha is divided by 255 because it has a value that ranges from 0 to 255.

Src.Red = Src.Red * SourceConstantAlpha / 255.0;
Src.Green = Src.Green * SourceConstantAlpha / 255.0;
Src.Blue = Src.Blue * SourceConstantAlpha / 255.0;
Src.Alpha = Src.Alpha * SourceConstantAlpha / 255.0;
Dst.Red = Src.Red  + (1 - Src.Alpha) * Dst.Red
Dst.Green = Src.Green + (1 - Src.Alpha) * Dst.Green
Dst.Blue = Src.Blue + (1 - Src.Alpha) * Dst.Blue
Dst.Alpha = Src.Alpha + (1 - Src.Alpha) * Dst.Alpha

Автор: Alexeis 13.4.2006, 11:00
Спасибо smile думаю тема исчерпана.

Автор: ~FoX~ 13.4.2006, 11:05
Код

  public
    { Public declarations }
  end;
  procedure LayeredDraw(x,y : integer; S,D : TBitmap; Layered : Integer);

Type
  TRGB=record
  b,g,r : byte;
  end;

    ARGB=array [0..1] of TRGB;
    PARGB=^ARGB;
    PRGB = ^TRGB;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure LayeredDraw(x,y : integer; S,D : TBitmap; Layered : Integer);
var
  i,j : integer;
  p1,p2 : PARGB;
begin
 for i:=0 to S.Height-1 do
 begin
  p1:=S.ScanLine[i];
  p2:=D.ScanLine[i+x];
  for j:=0 to S.Width-1 do
  begin
   p2[j+y].r:=Round(p2[j+y].r*(1-Layered/255)+p1[j].r*Layered/255);
   p2[j+y].g:=Round(p2[j+y].g*(1-Layered/255)+p1[j].g*Layered/255);
   p2[j+y].b:=Round(p2[j+y].b*(1-Layered/255)+p1[j].b*Layered/255);
  end;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Bit1, Bit2: TBitmap;
begin
  Bit1 := TBitmap.Create;
  Bit2 := TBitmap.Create;
  Bit1.LoadFromFile('c:\wall.bmp');
  Bit2.LoadFromFile('c:\1.bmp');
  LayeredDraw(150, 250, Bit2, Bit1, 100);
  Form1.Canvas.Brush.Bitmap := Bit1;
  Form1.Canvas.FillRect(Rect(0,0, Bit1.Width, Bit1.Height));
  Bit1.Free;
  Bit2.Free;
end;

end.


S - что рисовать, D - где рисовать, x,y - в каком месте на D нарисовать S. layered - прозрачность от 0 до 255

Автор: DelphiFun 28.1.2008, 03:00
Alexeis, а ты не объяснишь ли случаем, по каким формулам работает функция MixBytes в приведённом тобою асмовом коде?
(сорри, но в асме я не силён :( )

Автор: Alexeis 28.1.2008, 10:20
DelphiFun, да ничего особенно нового не делает (см пост http://forum.vingrad.ru/index.php?show_type=forum&showtopic=91526&unread=1&hl=#). Ее особенность только в том, что она смешивает не сами цвета, а отдельно их составляющие, но делает это при помощи целочисленных операций, поэтому теоретически это должно работать быстрее, но на практике большую часть времени занимает отрисовка битмапа, потому в данном случае это некритично smile .

Добавлено через 2 минуты и 38 секунд
FG - верхний слой 
BG - нижний слой 
TRANS - степень прозрачности от 0..255

формат пикселя может быть либо 24 либо 32 бита

Автор: DelphiFun 28.1.2008, 13:57
т.е. берёт верхний цвет в RGB: (155,126,250)
нижний слой, скажем: (128,190,10)
И чего с ними делает? smile
trans, например: 50

Автор: Alexeis 28.1.2008, 14:05
Цитата(DelphiFun @  28.1.2008,  12:57 Найти цитируемый пост)
И чего с ними делает? smile


blue :=  byte(((SrcAlpha) * Src.Blue + (255 - SrcAlpha) * Dst.Blue) / 255);

Автор: DelphiFun 28.1.2008, 14:10
а SrcAlpha это trans в нашем случае? или откуда берёться эта переменная?

Автор: Alexeis 28.1.2008, 14:21
Цитата(DelphiFun @  28.1.2008,  13:10 Найти цитируемый пост)
а SrcAlpha это trans в нашем случае?

угу

Автор: DelphiFun 28.1.2008, 14:38
ясно. Спасибо большое за объяснение! Как раз то, что мне и нужно!

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)