Как нарисовать TBitmap32 прозрачно на TBitmap?
Я пытаюсь нарисовать исходное изображение (GR32 TBitmap32), которое содержит некоторые полностью прозрачные, а также частично прозрачные пиксели на обычном (TBitmap) изображении, сохраняя при этом прозрачность исходного изображения.
Я использую это:
BMP32.DrawTo(BMP.Canvas.Handle, 0, 0);
но изображение не рисуется прозрачно.
Код:
Все довольно просто: у меня есть фоновое растровое изображение (Bkg), в котором я загружаю, при запуске приложения, изображение. Затем в процедуре "Применить" я загружаю второе изображение с диска (изображение с прозрачностью) и рисую его поверх фона.
var Bkg: TBitmap;
procedure TfrmPhoto.FormCreate(Sender: TObject);
begin
Bkg:= LoadGraphEx(GetAppDir+ 'bkg.bmp'); { Load bitmap from file }
{
Bkg.Transparent:= TRUE;
Bkg.PixelFormat:= pf32bit;
Bkg.TransparentColor:= clPink;
}
end;
procedure TfrmPhoto.Apply2;
VAR
Loader: TBitmap;
BMP32: tbitmap32;
begin
BMP32:= TBitmap32.Create;
TRY
Loader:= TBitmap.Create;
TRY
Loader.LoadFromFile('c:\Transparent.BMP');
BMP32.Assign(Loader);
FINALLY
FreeAndNil(Loader);
END;
{ Mix images }
BMP32.DrawTo(Bkg.Canvas.Handle, 0, 0); <----- The problem is here
imgPreview.Picture.Assign(Bkg); { This is a TImage where I see the result }
FINALLY
FreeAndNil(BMP32);
END;
end;
3 ответа
Это работало (но с 2 недостатками) с TransparentBlt().
Я не доволен тем, как TransparentBlt обрабатывает полупрозрачные пиксели (край поворотного изображения). После слияния изображения src с фоном края выглядят плохо.
Чтобы использовать TransparentBlt, мне нужно было определить цвет (clPink) в исходном изображении как прозрачный. Это означает, что если на исходном изображении есть немного розового, результат будет выглядеть очень неприятно (он будет считаться прозрачным). Помолимся за не розовые картинки!
Если вы найдете способ перенести изображение (при сохранении прозрачности) непосредственно из Bitmap32 в фоновый режим, пожалуйста, напишите, и я приму ваш ответ!
Решение (все еще взломанное), которое я вижу здесь, состоит в том, чтобы обработать все в TBitmap32 и затем "экспортировать" конечный результат как TBitmap. Я попробую это завтра.
Обновить:
Решение:
Вот как объединить два изображения TBitmap32, сохраняя прозрачность:
Dst.CombineMode:= cmBlend;
Dst.DrawMode:= dmBlend;
Src.Draw(0, 0, Dst);
Dst и Src являются изображениями TBitmap32. Это не работает с TBitmap.
Как уже было предложено вами, я бы порекомендовал выполнять операции смешивания полностью в домене TBitmap32! Причиной этого является тот факт, что он предлагает больше вариантов смешивания и использует MMX/SSE/SSE2, где это возможно (на современных машинах всегда так). С этим обычно можно получить заметное повышение производительности в отличие от разрешения GDI выполнять смешивание.
В частности, это не очень хорошая идея, поскольку GDI обычно не использует какие-либо коды операций SIMD (MMX/SSE).
Это также зависит от того, насколько изменяется каждая часть. Например, обычно фон довольно статичен и должен передаваться в TBitmpa32 только изредка при изменениях (например, при изменении стиля VCL или темы пользовательского интерфейса). С каждой передачей (GR32 <-> TBitmap и т. Д.) Может произойти преобразование имплика (DIB <-> DDB), что делает всю операцию смешивания O(n²). Поэтому вам лучше перевести (с неявным преобразованием) в TBitmap32 только один раз, а затем выполнить смешивание полностью в домене GR32.
Напротив, если TBitmap32 довольно статичен и TBitmap (или фон) сильно меняется, возможно, было бы лучше оставить GR32 в покое и скопировать TBitmap32 в TBitmap и выполнить смешивание с GDI. Несмотря на то, что смешивание GDI немного медленнее, вы избегаете дополнительной копии. В противном случае узким местом будет пропускная способность памяти, а скорость обработки никогда не сможет выйти за пределы.
Это dmBlend DrawMode TBitmap32 для включения прозрачности, но он работает только между двумя растровыми изображениями TBitmap32. Не используйте TBitmap32 с прозрачными изображениями для рисования непосредственно на HDC, Canvas или TBitmap. Используйте dmBlend и DrawTo или BlockTransfer() для рисования на другом TBitmap32. Например, для прозрачного рисования на TBitmap создайте промежуточный кэш TBitmap32:
- Скопируйте изображение из TBitmap в кэш TBitmap32;
- Примените ваше прозрачное изображение в кэш TBitmap32, используя DrawTo или BlockTransfer(), избегайте использования Canvas или HDC для смешивания двух изображений, поскольку они теряют информацию альфа-слоя;
- Скопируйте изображение обратно из кэша TBitmap32 в ваш TBitmap.