TPNGObject - создайте новое пустое изображение и нарисуйте на нем полупрозрачные изображения - PullRequest
5 голосов
/ 18 декабря 2011

Я создаю приложение с "виртуальными окнами".Выходные данные: TImage object.

1) Приложение загружает файлы скина окна в TPNGObject:

skin

2) Затем приложение должносоздайте новый бланк TPNGObject, измените размер файлов обложки до нужных размеров и нарисуйте их на этом пустом изображении.Должно выглядеть примерно так:

new form

3) И окончательный вывод на TImage:

output

Проблема в том,что я знаю, как создать полностью пустое изображение вне экрана.Конечно, я мог бы просто отображать файлы скина в TImage каждый раз, но проще и лучше изменить размер файлов скина и создать окно один раз.
Я использую библиотеку PNG от Gustavo Daud, версия 1.564(31 июля 2006 г.).

Ответы [ 4 ]

5 голосов
/ 20 декабря 2011

Ниже используется CreatePNG процедура 'pngfunctions.pas' Мартина Салли из библиотеки расширений (pngcomponents) для pngimage.

var
  Bmp, Mask: TBitmap;
  PNG: TPNGObject;
begin
  Bmp := TBitmap.Create;
  Bmp.PixelFormat := pf24bit;
  Bmp.SetSize(64, 64);

  Bmp.Canvas.Brush.Color := clBtnFace;
  Bmp.Canvas.Font.Color := clRed;
  Bmp.Canvas.Font.Size := 24;
  Bmp.Canvas.TextOut(4, 10, 'text');

  Mask := TBitmap.Create;
  Mask.PixelFormat := pf24bit;
  Mask.Canvas.Brush.Color := clBlack;
  Mask.SetSize(64, 64);
  Mask.Canvas.Font.Color := clWhite;
  Mask.Canvas.Font.Size := 24;
  Mask.Canvas.TextOut(4, 10, 'text');

  PNG := TPNGObject.Create;
  CreatePNG(Bmp, Mask, PNG, False);
  PNG.Draw(Canvas, Rect(10, 10, 74, 74));

  // finally, free etc...


Вот вывод (черные, белые квадраты - это формы TS):

enter image description here

2 голосов
/ 03 января 2012

Я прошу прощения у людей, что я испортил им голову.

Оказывается CreateBlank работает как хотел. Проблема заключалась в том, что я рисовал PNG на холсте PNG (PNG.Canvas.Draw). Canvas на самом деле не поддерживает прозрачность. Чтобы нарисовать полупрозрачный PNG на другом PNG, вам понадобится процедура / функция, которая объединяет оба слоя вместе. С некоторым поиском в Google я закончил эту процедуру:

procedure MergePNGLayer(Layer1, Layer2: TPNGObject; Const aLeft, aTop: Integer);
var
  x, y: Integer;
  SL1,  SL2,  SLBlended: pRGBLine;
  aSL1, aSL2, aSLBlended: PByteArray;
  blendCoeff: single;
  blendedPNG, Lay2buff: TPNGObject;
begin
  blendedPNG := TPNGObject.Create;
  blendedPNG.Assign(Layer1);
  Lay2buff:=TPNGObject.Create;
  Lay2buff.Assign(Layer2);
  SetPNGCanvasSize(Layer2, Layer1.Width, Layer1.Height, aLeft, aTop);
  for y := 0 to Layer1.Height - 1 do
  begin
    SL1 := Layer1.Scanline[y];
    SL2 := Layer2.Scanline[y];
    aSL1 := Layer1.AlphaScanline[y];
    aSL2 := Layer2.AlphaScanline[y];
    SLBlended := blendedPNG.Scanline[y];
    aSLBlended := blendedPNG.AlphaScanline[y];
    for x := 0 to Layer1.Width - 1 do
    begin
      blendCoeff:=aSL1[x] * 100/255/100;
      aSLBlended[x] := round(aSL2[x] + (aSL1[x]-aSL2[x]) * blendCoeff);
      SLBlended[x].rgbtRed   := round(SL2[x].rgbtRed + (SL1[x].rgbtRed-SL2[x].rgbtRed) * blendCoeff);
      SLBlended[x].rgbtGreen := round(SL2[x].rgbtGreen + (SL1[x].rgbtGreen-SL2[x].rgbtGreen) * blendCoeff);
      SLBlended[x].rgbtBlue  := round(SL2[x].rgbtBlue + (SL1[x].rgbtBlue-SL2[x].rgbtBlue) * blendCoeff);
    end;
  end;
  Layer1.Assign(blendedPNG);
  Layer2.Assign(Lay2buff);
  blendedPNG.Free;
  Lay2buff.Free;
end;


Использование:

var
  PNG1, PNG2: TPNGObject;
begin
  PNG1 := TPNGObject.CreateBlank(COLOR_RGBALPHA, 16, 500, 500);
  PNG2 := TPNGObject.Create;
  PNG2.LoadFromFile('...*.png');
  MergePNGLayer(PNG1, PNG2, 0, 0);
  // PNG1 is the output

И снова мне очень жаль пользователей, которые хотели помочь, но не смогли из-за того, что не поняли меня.

2 голосов
/ 19 декабря 2011

Мой другой ответ - еще одна альтернатива, которую я предлагаю. Однако ваш вопрос по-прежнему создает проблему: в библиотеке PNG должна быть ошибка, которая препятствует отображению любого холста (после использования конструктора CreateBlank с COLOR_RGBALPHA в качестве цветного типа), или мы все что-то упустили.

Похоже, что единственный обходной путь, который я вижу, - это (как вы упомянули в своем редактировании) использовать вместо этого растровое изображение для рисования. Используйте прозрачные свойства этого растрового изображения (Transparent: Bool и TransparentColor: TColor), чтобы установить прозрачную область вашего изображения, затем, когда вам нужен прозрачный PNG, просто скопируйте это растровое изображение в новый объект PNG ...

BMP.Width:= 100;
BMP.Height:= 100;
BMP.Transparent:= True;
BMP.TransparentColor:= clWhite;
BMP.Canvas.Brush.Style:= bsSolid;
BMP.Canvas.Brush.Color:= clWhite;
BMP.Canvas.FillRect(BMP.Canvas.ClipRect);
BMP.Canvas.Brush.Color:= clBlue;
BMP.Canvas.Ellipse(10, 10, 90, 90);
PNG.Assign(BMP);

А белая область изображения должна быть прозрачной. Существуют и другие способы достижения прозрачной области, но это другой вопрос.

Изображение:

Это то, что вы пытаетесь сделать?

enter image description here

0 голосов
/ 19 декабря 2011

У меня нет ответа на этот вопрос, но я понял, как получить тот же результат с любым редактором PNG. Я создал пустое изображение PNG 1000x1000 и сохранил его в своем каталоге приложений. Затем я открываю это изображение в моей программе и изменяю размер изображения до необходимых размеров (конечно, меньшего размера), и в этом вся хитрость.

...