Вопрос по winapi – Как смешать цвета (раскрасить указанным альфа-значением) область холста, используя чистый GDI?

8

Я хотел бы смешать цвета (раскрасить по заданному альфа-значению) области холста, используя чистыйWindows GDI (то есть без GDI +, DirectX или подобного, без OpenGL, без ассемблера или сторонних библиотек).

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

<code>procedure ColorBlend(const ACanvas: HDC; const ARect: TRect;
  const ABlendColor: TColor; const ABlendValue: Integer);
var
  DC: HDC;
  Brush: HBRUSH;
  Bitmap: HBITMAP;
  BlendFunction: TBlendFunction;
begin
  DC := CreateCompatibleDC(ACanvas);
  Bitmap := CreateCompatibleBitmap(ACanvas, ARect.Right - ARect.Left,
    ARect.Bottom - ARect.Top);
  Brush := CreateSolidBrush(ColorToRGB(ABlendColor));
  try
    SelectObject(DC, Bitmap);
    Windows.FillRect(DC, Rect(0, 0, ARect.Right - ARect.Left,
      ARect.Bottom - ARect.Top), Brush);
    BlendFunction.BlendOp := AC_SRC_OVER;
    BlendFunction.BlendFlags := 0;
    BlendFunction.AlphaFormat := 0;
    BlendFunction.SourceConstantAlpha := ABlendValue;
    Windows.AlphaBlend(ACanvas, ARect.Left, ARect.Top,
      ARect.Right - ARect.Left, ARect.Bottom - ARect.Top, DC, 0, 0,
      ARect.Right - ARect.Left, ARect.Bottom - ARect.Top, BlendFunction);
  finally
    DeleteObject(Brush);
    DeleteObject(Bitmap);
    DeleteDC(DC);
  end;
end;
</code>

Чтобы понять, что должна делать эта функция, смотрите следующие (различающие :-) изображения:

И код, который может отрисовыватьthis image в верхней левой части формы, как показано выше:

<code>uses
  PNGImage;

procedure TForm1.Button1Click(Sender: TObject);
var
  Image: TPNGImage;
begin
  Image := TPNGImage.Create;
  try
    Image.LoadFromFile('d:\6G3Eg.png');
    ColorBlend(Image.Canvas.Handle, Image.Canvas.ClipRect, $0000FF80, 175);
    Canvas.Draw(0, 0, Image);
  finally
    Image.Free;
  end;
end;
</code>

Есть ли более эффективный способ сделать это, используя чистый GDI или Delphi VCL?

Почему ты думаешь, что то, что у тебя уже есть, неэффективно? Remy Lebeau
Вот почему я спросил. Я знаю, что это эффективно, но я хочу больше (если возможно: -) TLama
@ TLama: Эти статьи может быть интересно. Uli Gerhardt
Почувствуйте, что вы используете com-интерфейс Windows Api, почему бы не использовать Direct 2D? это быстрее (если ваша система Windows Vista / 7). Есть на что посмотреть;) johnathan
AlphaBlend() являетс простой способ сделать это - пусть ОС сделает всю работу. В противном случае вам придется напрямую управлять пикселями PNG. Единственная оптимизация, которую вы могли бы сделать дальше, - это создать сплошное растровое изображение один раз и использовать его снова и снова. Remy Lebeau

Ваш Ответ

1   ответ
4

что-то тип

Canvas.Draw(Arect.Left, ARect.Top, ABitmap, AAlphaBlendValue);

комбинируется с FillRect для смешанного цвета

Обновит: А вот код, максимально приближенный к вашему интерфейсу, но чистый VCL.
Может быть не так эффективно, но гораздо проще (и несколько портативно).
Как сказал Реми, чтобы рисовать на форме псевдопостоянным способом, тебе придется использовать OnPaint ...

procedure ColorBlend(const ACanvas: TCanvas; const ARect: TRect;
  const ABlendColor: TColor; const ABlendValue: Integer);
var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;
  try
    bmp.Canvas.Brush.Color := ABlendColor;
    bmp.Width := ARect.Right - ARect.Left;
    bmp.Height := ARect.Bottom - ARect.Top;
    bmp.Canvas.FillRect(Rect(0,0,bmp.Width, bmp.Height));
    ACanvas.Draw(ARect.Left, ARect.Top, bmp, ABlendValue);
  finally
    bmp.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Image: TPNGImage;
begin
  Image := TPNGImage.Create;
  try
    Image.LoadFromFile('d:\6G3Eg.png');
    ColorBlend(Image.Canvas, Image.Canvas.ClipRect, $0000FF80, 175);
    Canvas.Draw(0, 0, Image);
    // then for fun do it to the Form itself
    ColorBlend(Canvas, ClientRect, clYellow, 15);
  finally
    Image.Free;
  end;
end;
TheFillRect звонок не нужен. При изменении размера растрового изображения в качестве фона будет использоваться цвет кисти. Sertac Akyuz
+ 1, спасибо! Я никогда не видел эту перегрузку раньше (у меня Delphi 2009 вручную). Приятно узнавать что-то новое, но мне нужно применить эффект colorize. TLama
Вы можете создать сплошное растровое изображение какTBitmap объект иDraw() это с альфа указанным на вашем изображенииCanvas, тогдаDraw() готовое изображение на вашей форме. Кстати, если вы хотите, чтобы окончательный рисунок был постоянным, вы должны нарисовать его на форме из ееOnPaint событие, а не в кнопкеOnClick мероприятие. Вы можете подготовить изображение вOnClick событие, а затемInvalidate() форму, чтобы вызвать перерисовку, а затем рисовать текущее изображение всякий раз, когдаOnPaint событие запущено. Или просто поместите окончательное изображение вTImage составная часть Remy Lebeau
Франсуа, принято, спасибо! Btw.bmp.Canvas.FillRect(bmp.Canvas.ClipRect); может также пригодиться ;-) @Remy, спасибо за примечание о постоянстве рисования, но здесь это не нужно, так как эта функция была предназначена для использования в VirtualTreeView'sOnBeforeCellPaint где фон может быть анимирован, например (я забыл упомянуть об этом, мой плохой). TLama
@ TLama, конечно, но Canvas.ClipRect включает в себя немного больше, чем просто построение Rect. Так что вместо этого я пошел набирать тексты ...; -) François

Похожие вопросы