7th
Май

Изменение размера PNG без потери прозрачности

Posted by bullvinkle under Пост-обзор

Всем привет! Попал в такую ситуацию: есть 2 временных TPNGImage; один загружен из файла, второй – пустой, предназначен для вывода растянутого/ужатого первого.

При копировании первого во второй и его последующем ресайзе теряется альфа-канал.

Как можно заново просчитать маску прозрачности (или как это делается), учитывая новые размеры?

Код:


var
  Src,Dst:TPngImage;

type
  PRGBAArray = ^TRGBAArray;
  TRGBAArray = array[0..MaxPixelCountA-1] of TRGBQuad;
...
procedure Resize;
var BTOut:TBitmap;
    BT:Tbitmap;
    bt_tmp_rgb,bt_tmp_a:tbitmap;
    bt_tmp_rgb2,bt_tmp_a2:tbitmap;
    iii,ii:integer;
    fff:PRGBAArray;
    aaa:pByteArray;
begin
  BTOut:=TBitmap.Create;
  BTOut.PixelFormat:=pf32bit;

  BT:=TBitmap.Create;
  BT.PixelFormat:=pf32bit;

  bt_tmp_rgb:=TBitmap.Create;
  bt_tmp_a:=TBitmap.Create;
  bt_tmp_rgb.PixelFormat:=pf32bit;
  bt_tmp_a.PixelFormat:=pf32bit;

  BT.Assign(Src);
  for ii:=0 to BT.Height-1 do begin
    fff:=BT.ScanLine[ii];
    aaa:=Src.AlphaScanline[ii];
    for iii:=0 to BT.Width-1 do begin
      fff[iii].rgbReserved:=aaa[iii];
    end;
  end;
  BTOut.SetSize(Dst.Width,Dst.Height);
  bt_tmp_rgb.SetSize(BT.Width,BT.Height);
  bt_tmp_a.SetSize(BT.Width,BT.Height);

  //Разделяем битмап-подложку на "видимый" битмап RGB и альфаканал
  GetLayerBitmap(bt,bt_tmp_rgb,bt_tmp_a);
  BT.Free;
  bt_tmp_rgb2:=TBitmap.Create;
  bt_tmp_rgb2.PixelFormat:=pf32bit;
  bt_tmp_rgb2.SetSize(BTOut.Width,BTOut.Height);
  bt_tmp_rgb2.Canvas.StretchDraw(bt_tmp_rgb2.Canvas.ClipRect,bt_tmp_rgb);
  bt_tmp_rgb.Free;
  bt_tmp_a2:=TBitmap.Create;
  bt_tmp_a2.PixelFormat:=pf32bit;
  bt_tmp_a2.SetSize(BTOut.Width,BTOut.Height);
  bt_tmp_a2.Canvas.StretchDraw(bt_tmp_a2.Canvas.ClipRect,bt_tmp_a);
  bt_tmp_a.Free;

  //собираем временные битмапы в один 32-битный, который потом будет отображен
  Build32(bt_tmp_rgb2,bt_tmp_a2,BTOut);
  bt_tmp_rgb2.Free;
  bt_tmp_a2.Free;
  Dst.Assign(BTOut);
  Dst.CreateAlpha;

  for ii:=0 to BTOut.Height-1 do begin
    fff:=BTOut.ScanLine[ii];
    aaa:=Layer.StretchPNG.AlphaScanline[ii];
    for iii:=0 to BTOut.Width-1 do begin
      aaa[iii]:=fff[iii].rgbReserved;
    end;
  end;

  BTOut.Free;
end;

procedure GetLayerBitmap(_B_res:TBitmap;  _Brgb,_Bmask:Tbitmap);
var x, y: Integer; RowOut,RowIn,RowOutM: PRGBAArray;
begin
  for y:=0 to _B_res.Height-1 do begin
    RowOut:= _Brgb.ScanLine[y];
    RowOutM:= _Bmask.ScanLine[y];
    RowIn:= _B_res.ScanLine[y];
    for x:=0 to _B_res.Width-1 do begin

     RowOutM[x].rgbReserved:=255;
     RowOutM[x].rgbBlue:=RowIn[x].rgbReserved;
     RowOutM[x].rgbGreen:=RowIn[x].rgbReserved;
     RowOutM[x].rgbRed:=RowIn[x].rgbReserved;

     RowOut[x].rgbReserved:=255;
     RowOut[x].rgbBlue:=RowIn[x].rgbBlue;
     RowOut[x].rgbGreen:=RowIn[x].rgbGreen;
     RowOut[x].rgbRed:=RowIn[x].rgbRed;
     end;
  end;
end;

procedure Build32(_B_in,_B_inM:TBitmap; _Bout:Tbitmap);
var x, y: Integer; RowOut: PRGBAArray; RowIn,RowM:PRGBAArray;
begin
  for y:=0 to _B_in.Height-1 do begin
     RowOut:= _Bout.ScanLine[y];
     RowIn:= _B_in.ScanLine[y];
     RowM:= _B_inM.ScanLine[y];
    for x:=0 to _B_in.Width-1 do begin
          RowOut[x].rgbBlue:=RowIn[x].rgbBlue;
          RowOut[x].rgbGreen:=RowIn[x].rgbGreen;
          RowOut[x].rgbRed:=RowIn[x].rgbRed;
          RowOut[x].rgbReserved:=RowM[x].rgbRed;
    end;
  end;
end;

Тема на форуме.

Похожие статьи