Преобразование png в bmp (с сохранением прозрачности)

Я использую delphi XE-5 и загружаю информацию о кнопках из файла JSON, чтобы создать кнопки в элементе управления TMS ADVToolBar. Каждая кнопка 50X35 и в формате png с прозрачностью.

Я получаю каждый URL-адрес, используя компонент idHTTP для извлечения его в поток, а затем загружаю в png. Затем я рисую его на прозрачном BMP. Однако я не думаю, что это правильный путь. В любом случае, bmp затем добавляется в TImageList, где он назначается кнопке с использованием индекса. Изображение отображается на кнопке, но без прозрачности.

см. мой код ниже:

 imgUrl:= //code to get img url from JSON file;

 MS := TMemoryStream.Create;
 png := TPngImage.Create;
 png.Transparent:= True;
 try
  idHTTP1.get(imgUrl,MS);
  Ms.Seek(0,soFromBeginning);
  png.LoadFromStream(MS);
  bmp:= TBitmap.Create;
  bmp.Transparent:= True;
  bmp.Width:= 50;
  bmp.Height:= 50;
  png.Draw(bmp.Canvas, Rect(7, 7, png.Width, png.Height));
  ImageList1.Add(bmp, nil);
  AdvGlowBtn.Images:= ImageList1;
  AdvGlowBtn.Layout:= blGlyphTop;
  AdvGlowBtn.WordWrap:= False;
  AdvGlowBtn.AutoSize:= True;

  AdvGlowBtn.ImageIndex:= ImageList1.Count-1;

  bmp.Free;
 finally
 FreeAndNil(png);
 FreeAndNil(MS);
 end;

person LuvRAD    schedule 27.01.2014    source источник
comment
Вероятно, вы не хотите Transparent. Вы, вероятно, хотите растровое изображение 32bpp.   -  person David Heffernan    schedule 27.01.2014
comment
Почему вы не используете PNG напрямую, а конвертируете его в BMP?   -  person Vinícius Gobbo A. de Oliveira    schedule 27.01.2014
comment
Попробуйте GraphicEx или Vampyre Imaging... но лучше всего использовать напрямую PNG   -  person Arioch 'The    schedule 27.01.2014
comment
@Arioch, это так же просто as this без третьих лиц ... Но лучше всего добавлять PNG напрямую.   -  person TLama    schedule 27.01.2014
comment
@TLama - это правда? Размер глифа TImageList должен быть пропорционален, не так ли? (например, 50X50) В этом случае изображения, поступающие из Интернета, имеют размер 50X35. Я получаю ошибки Invalid Image Size.   -  person LuvRAD    schedule 27.01.2014
comment
@LuvRAD, метод Assign также принимает размер исходной графики. Ну, эта разница в размере очень важная деталь (я взял размер, который вы упомянули, как опечатку по сравнению с вашим кодом). Итак, вы на самом деле хотите обрезать или растянуть их, сохраняя прозрачность...   -  person TLama    schedule 27.01.2014
comment
@ Винисиус Гоббо А. де Оливейра, потому что я пытаюсь решить проблему с размером изображения 50X35. Как мне поместить их в TIMageList и использовать их по их свойству индекса, не выдавая ошибку Invalid Image   -  person LuvRAD    schedule 27.01.2014
comment
@TLama - как насчет TImaeList. Как поместить 50X35 в TIMageList, который должен быть 50X50?   -  person LuvRAD    schedule 27.01.2014
comment
@ Винисиус Гоббо А. де Оливейра - использование PNG напрямую создает [Ошибка dcc32] UntMain.pas (117): E2010 Несовместимые типы: ошибка «TBitmap» и «TPngImage» при добавлении png в TImageList   -  person LuvRAD    schedule 27.01.2014
comment
@TLama - Но лучше всего добавить PNG напрямую - как добавить PNG непосредственно в TImageList?   -  person LuvRAD    schedule 27.01.2014
comment
@LuvRAD, извини. Это опечатка. Я хотел сказать использовать вместо добавить. Кстати. не могли бы вы уточнить, какова ваша цель, пожалуйста? Каким-то образом скрыто, что вы хотите изменить его размер, сохранив прозрачность, прежде чем добавлять в список изображений. За исключением того, что нам нужно знать, хотите ли вы обрезать его или растянуть до целевого размера.   -  person TLama    schedule 27.01.2014
comment
Моя цель — просто взять изображения, которые уже есть в Интернете (на нашем хост-сайте), и поместить их на кнопки. По сути, я создаю элемент управления TRibbon (на самом деле это версия программного обеспечения TMS) во время выполнения, все его вкладки, группы и кнопки берутся из файла JSON. URL-адрес каждого глифа кнопки также находится в этом файле JSON. К сожалению, все изображения имеют размер 50x35. Мне нужно разместить эти глифы на кнопках как прозрачные. У меня нет проблем с получением изображений на кнопках, к сожалению, все они имеют белый фон. Однако они прозрачны в Интернете как PNG.   -  person LuvRAD    schedule 27.01.2014
comment
Итак, я думаю, это означает, что мне нужно растянуть png? Я не знаю? Может ли TImageList принять изображение размером 50X35? Потому что я продолжаю получать недопустимые ошибки размера изображения, если это не так.   -  person LuvRAD    schedule 27.01.2014
comment
давайте продолжим это обсуждение в чате   -  person LuvRAD    schedule 27.01.2014


Ответы (4)


Сначала вам нужно включить темы выполнения (Менеджер проектов), иначе у вас не будет прозрачности ваших изображений.

И это код для загрузки изображения PNG в ваш ImageList1

bmp := TBitmap.Create;
try
  // everything done before to bmp has no effect
  bmp.Assign( png );
  // if for some reason the loaded image is smaller
  // set the size to avoid the invalid image size error
  bmp.Width := ImageList1.Width;
  bmp.Height := ImageList1.Height;

  AdvGlowBtn.Images:= ImageList1;
  ...
  // now add the Bitmap to the ImageList
  AdvGlowBtn.ImageIndex := ImageList1.Add( bmp, nil );
finally
  bmp.Free;
end;
person Sir Rufo    schedule 27.01.2014
comment
Это, скорее всего, хорошее решение, но оно не работает для меня, так как я не упомянул, что мои png-изображения имеют разные размеры (самый большой из них 50X35). - person LuvRAD; 02.02.2014
comment
Извините, но я могу ответить только на заданные вопросы. Теперь вы знаете, как конвертировать PNG в Bitmap без потери прозрачности. Если у вас есть другой вопрос, вы должны задать другой вопрос. - person Sir Rufo; 02.02.2014

У меня есть старый проект в Delphi 5, и я до сих пор иногда его использую. Это мое решение с использованием объекта png.

procedure ImageList2Alpha(const ImageList: TImageList);
const
  Mask: array[Boolean] of Longint = (0, ILC_MASK);
var
  TempList: TImageList;
begin
  if Assigned(ImageList) then
  begin
    TempList := TImageList.Create(nil);
    try
      TempList.Assign(ImageList);
      with ImageList do
      begin
        Handle := ImageList_Create(Width, Height, ILC_COLOR32 or Mask[Masked], 0, AllocBy);
        if not HandleAllocated then
          raise EInvalidOperation.Create(SInvalidImageList);
      end;
      Imagelist.AddImages(TempList);
    finally
      FreeAndNil(TempList);
    end;
  end;
end;

procedure LoadPngToBmp(var Dest: TBitmap; AFilename: TFilename);
type 
  TRGB32 = packed record 
    B, G, R, A : Byte;
  end; 
  PRGBArray32 = ^TRGBArray32; 
  TRGBArray32 = array[0..0] of TRGB32;
type
  TRG24 = packed record
    rgbtBlue, rgbtGreen, rgbtRed : Byte;
  end;
  PRGBArray24 = ^TPRGBArray24;
  TPRGBArray24 = array[0..0] of TRG24;
type
  TByteArray = Array[Word] of Byte;
  PByteArray = ^TByteArray;
  TPByteArray = array[0..0] of TByteArray;
var
  BMP : TBitmap;
  PNG: TPNGObject;
  x, y: Integer; 
  BmpRow: PRGBArray32;
  PngRow : PRGBArray24;
  AlphaRow: PByteArray;
begin

  Bmp := TBitmap.Create;
  PNG := TPNGObject.Create;

  try

    if AFilename <> '' then
    begin

      PNG.LoadFromFile(AFilename);
      BMP.PixelFormat := pf32bit;
      BMP.Height := PNG.Height;
      BMP.Width := PNG.Width;

      if ( PNG.TransparencyMode = ptmPartial ) then
      begin

        for Y := 0 to BMP.Height-1 do
        begin

          BmpRow := PRGBArray32(BMP.ScanLine[Y]);
          PngRow := PRGBArray24(PNG.ScanLine[Y]);
          AlphaRow := PByteArray(PNG.AlphaScanline[Y]);

          for X := 0 to BMP.Width - 1 do
          begin
            with BmpRow[X] do
            begin
              with PngRow[X] do
              begin
                R := rgbtRed; G := rgbtGreen; B := rgbtBlue;
              end;
              A := Byte(AlphaRow[X]);
            end;
          end;

        end;

      end else
      begin

        for Y := 0 to BMP.Height-1 do
        begin

          BmpRow := PRGBArray32(BMP.ScanLine[Y]);
          PngRow := PRGBArray24(PNG.ScanLine[Y]);

          for X := 0 to BMP.Width - 1 do
          begin
            with BmpRow[X] do
            begin
              with PngRow[X] do
              begin
                R := rgbtRed; G := rgbtGreen; B := rgbtBlue;
              end;
              A := 255;
            end;
          end;

        end;

      end;

      Dest.Assign(BMP);

    end;

  finally
    Bmp.Free;
    PNG.Free;
  end;
end;

Вызовите ImageList2Alpha(YourImageList) в OnCreate формы (FormCreate), и ImageList будет готов хранить ваши Bitmap32, сохраняя прозрачность.

Вызовите процедуру LoadPngToBmp, чтобы преобразовать PNG в Bitmap32, а затем сохраните его в своем ImageList.

person Sylvio Ruiz Neto    schedule 24.08.2017
comment
Оно работает. :) И для компиляции добавил эти модули в раздел uses: Winapi.CommCtrl, Vcl.Consts. - person JH Jang; 19.06.2018

Класс TBitmap использует собственные библиотеки Windows для управления растровыми изображениями. В зависимости от вашей версии Windows, базовые библиотеки операционной системы не поддерживают 32-битные BMP, несмотря на то, что файлы заголовков библиотек объявляют структуру BITMAPQUAD.

Для более новых версий Windows (наверное, Vista и выше) поле BITMAPQUAD.reserved используется для хранения альфа-канала. Для более старых версий это поле должно оставаться нулевым (0x00).

Если вы используете «последнюю» версию Windows, единственное возможное объяснение, которое я вижу, это то, что класс TBitmap не был обновлен для поддержки альфа-канала.

Использование класса TPNGImage не должно быть проблемой вместо его преобразования в BMP перед использованием, если только у вас нет особых потребностей.

person Vinícius Gobbo A. de Oliveira    schedule 27.01.2014
comment
Я почти уверен, что XP поддерживает альфа-канал в растровых изображениях. И не выиграл 2к. - person David Heffernan; 27.01.2014
comment
более конкретные потребности изложены в начальном посте. Как получить png 50X35 в ImageList и сохранить его прозрачность, чтобы я мог разместить их на кнопке - person LuvRAD; 27.01.2014
comment
@LuvRAD В документах указано, что он поддерживается, но, как вы заметили, нет возможности добавить TPNGImage непосредственно в TImageList. Я нахожу это отсутствие документации тревожным. docwiki.embarcadero.com/Libraries/XE5/en/ - person Vinícius Gobbo A. de Oliveira; 27.01.2014

Используйте это так:

ABitmap.SetSize(png.Width, png.Height);
png.AssignTo(ABitmap);
person dwrbudr    schedule 24.08.2017