*.bmp теряет прозрачный фон при использовании элемента управления ImageList v6

Извините, мой английский не очень хорош.

Мне нужно использовать полупрозрачные растровые изображения в моем приложении D7. Итак, я должен использовать XPManifest и ImageList версии 6 вместо стандартной версии 5.8. Но в этом случае я столкнулся с проблемой: все изображения теряют свою прозрачность, пока я загружаю их из потока!

type
  TForm2 = class(TForm)
    btn4: TButton;
    btn5: TButton;
    lst1: TbtkListView;
    il1: TImageList;
    btn1: TButton;
    tlb1: TToolBar;
    btn2: TToolButton;
    btn3: TToolButton;
    xpmnfst1: TXPManifest;
    procedure btn4Click(Sender: TObject);
    procedure btn5Click(Sender: TObject);
    procedure btn1Click(Sender: TObject);
  private
    FS: TFileStream;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.btn4Click(Sender: TObject);
var
  Bmp       : TBitmap;
  ImageList: TbtkImageList;
begin
  ImageList := TbtkImageList.Create(nil);
  Bmp       := TBitmap.Create;
  FS        := TFileStream.Create('c:\temp\1.cmp',fmCreate);
  try
    Bmp.LoadFromFile('c:\temp\1.bmp');
    ImageList.Add(Bmp, nil);
    FS.WriteComponent(ImageList);
  finally
    Bmp.Free;
  end;
end;

procedure TForm2.btn5Click(Sender: TObject);
var
  Bmp       : TBitmap;
  ImageList : TbtkImageList;
begin
  ImageList := TbtkImageList.Create(nil);
  Bmp := TBitmap.Create;
  try
    FS.Position := 0;
    FS.ReadComponent(ImageList);
    ImageList.GetBitmap(0, Bmp);
    Bmp.SaveToFile('c:\temp\3.bmp');
  finally
    Bmp.Free;
    ImageList.Free;
  end;
end;

ImageListCreationCode:
constructor TbtkImageList.Create(AOwner: TComponent);
begin
  inherited;

  if HandleAllocated then
    ImageList_Destroy(Handle);
  Handle := ImageList_Create(32, 32, ILC_COLOR32, AllocBy, AllocBy);
end;

http://s020.radikal.ru/i720/1403/36/c2702a8b5c1a.png До http://s001.radikal.ru/i195/1403/e2/1dd5ff14aa51.png После

Кто-нибудь может мне помочь?


person user1443993    schedule 04.03.2014    source источник
comment
@Ken Этот вопрос другой. Там пользователь пытался работать с элементом управления comctl32 v5.8.   -  person David Heffernan    schedule 05.03.2014
comment
@user Я не вижу доказательств того, что список изображений когда-либо был прозрачным. Вы нигде не устанавливаете глубину цвета. IIRC этого свойства не существует в D7, и вам нужно создать дескриптор списка изображений вручную.   -  person David Heffernan    schedule 05.03.2014
comment
Дэвид Хеффернан, извините, забыл добавить этот кусок кода. Исправлено.   -  person user1443993    schedule 05.03.2014
comment
@SertacAkyuz, но TBitmap не является потомком TComponent. Мы можем передавать только компоненты. Полагаю, я просто делаю что-то не так. Должно быть красивое решение...   -  person user1443993    schedule 05.03.2014
comment
В порядке. Это выглядит хорошо. Где теряется прозрачность? Мои инстинкты подсказывали мне, что сохранение/загрузка в/из .bmp — это настоящая проблема.   -  person David Heffernan    schedule 05.03.2014
comment
Прозрачность теряется при чтении потока. btn4Click записывает список в файл. После этого снова запускаем приложение и нажимаем btn5Click. Если мы используем приложение с v6 comctrl, 3.bmp портится. Но в случае, если мы используем v5.8 conctrl, 3.bmp подойдет.   -  person user1443993    schedule 05.03.2014
comment
@user - я не хотел использовать Read/WriteComponent для TBitmaps, просто загружайте/сохраняйте их так, как вам нравится. В любом случае, поскольку я не уверен, что это поможет, я удалил комментарий. Но вы можете попробовать и посмотреть, оставить список изображений в покое, загрузить растровое изображение, сохранить его, загрузить, ... прозрачный?   -  person Sertac Akyuz    schedule 05.03.2014
comment
@SertacAkyuz, тогда я должен разработать механизм сериализации растрового изображения. Я полагаю, это очень дорого и может делать ошибки. Не может быть, чтобы новый ImageList поддерживал полупрозрачность, но не мог транслировать прозрачные растровые изображения! Это должно быть что-то не так в моем собственном коде!   -  person user1443993    schedule 05.03.2014
comment
@user - Ну, я даже не знаю, решит ли это проблему. Суть была в том, чтобы изолировать проблему.   -  person Sertac Akyuz    schedule 05.03.2014
comment
@SertacAkyuz Ага, есть метод TBitmap.SaveToStream))) Да в данном случае все в порядке)   -  person user1443993    schedule 05.03.2014
comment
@user - это не ваш код неправильный (ну, кроме утечки списка изображений, неуместной попытки, наконец ..). ImageList.GetBitmap не сохраняет альфа-канал, он просто рисует на холсте переданного растрового изображения.   -  person Sertac Akyuz    schedule 05.03.2014


Ответы (2)


Как только вы поместите растровое изображение с информацией об альфа-канале в список изображений, нет простого (*) способа получить его в исходной растровой форме. TImageList.GetBitmap просто устанавливает размеры растрового изображения, которое вы ему передаете, и рисует на своем холсте. Он не использует перегрузку, которая могла бы прозрачно рисовать BTW, но это не так важно, поскольку вместо использования GetBitmap вы можете сами вызвать перегрузку Draw.

В результате вместо потоковой передачи списка изображений я предлагаю передавать сами растровые изображения, если вам нужно сохранить их первоначальную форму.


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

var
  Bmp       : TBitmap;
  ImageList : TImageList;
  FS: TFileStream;
begin
  ImageList := TImageList.Create(nil);
    try
      FS := TFileStream.Create('c:\temp\1.cmp',fmOpenRead or fmShareDenyWrite);
      try
        FS.ReadComponent(ImageList);
      finally
        FS.Free;
      end;
      Bmp := TBitmap.Create;
      try
        Bmp.PixelFormat := pf32bit;
        Bmp.Canvas.Brush.Color := clNone;
        Bmp.Width := ImageList.Width;
        Bmp.Height := ImageList.Height;
        ImageList.Draw(Bmp.Canvas, 0, 0, 0, dsNormal, itImage);
        Bmp.SaveToFile('c:\temp\3.bmp');
      finally
        Bmp.Free;
      end;
  finally
    ImageList.Free;
  end;
end;
person Sertac Akyuz    schedule 05.03.2014
comment
(*) - Это может быть даже невозможно. Деталь реализации ОС заключается в том, сохраняет ли список изображений после добавления растрового изображения точную информацию, которая содержалась в растровом изображении, или нет. Чего я не знаю. - person Sertac Akyuz; 06.03.2014
comment
На самом деле это не соответствует моим требованиям. Потому что я должен копировать ImageLists, но ImageList2.Assign(ImageList) портит изображения. Кроме того, ImageList2.add(BMP, nil); убивает прозрачность =( - person user1443993; 06.03.2014
comment
ImageList2.add(BMP, ноль); будет работать нормально и сохранит прозрачность, если BMP был загружен из файла, но не будет работать, если он был загружен из списка десериализованных изображений.. Я не понимаю, почему =( - person user1443993; 06.03.2014
comment
@user - я попытался объяснить причину в ответе: списки изображений не являются хранилищами растровых изображений. Кроме того, я мог только попытаться помочь с тем, что спросили. жаль не помогает.. - person Sertac Akyuz; 06.03.2014
comment
@user - я только что проверил добавление «Bmp» в другой список изображений, созданный как первый, и он выглядит таким же прозрачным. В любом случае, я отрицаю вопрос, поскольку он, по-видимому, не спрашивает, что вы намеревались спросить, поскольку работа кода в нем не считается ответом. - person Sertac Akyuz; 11.03.2014

Я полагаю, я нашел своего рода решение.

var
  BMP: TBitmap;
  ImageList : TImageList;
  FS: TFileStream;
  ico: TIcon;
  IconInfo: TIconInfo;
begin
  ImageList := TImageList.Create(nil);
    try
      FS := TFileStream.Create('c:\temp\1.cmp',fmOpenRead or fmShareDenyWrite);
      try
        FS.ReadComponent(ImageList);
      finally
        FS.Free;
      end;
      Bmp := TBitmap.Create;
      Ico := TIcon.Create;
      try
        ImageList.GetIcon(0, ico);

        GetIconInfo(ico.Handle, IconInfo);

        BMP.Handle := IconInfo.hbmColor;
        BMP.PixelFormat := pf32bit;
        BMP.Canvas.Brush.Color := clNone;

        Bmp.SaveToFile('c:\temp\3.bmp');
      finally
        ico.Free;
        Bmp.Free;
      end;
  finally
    ImageList.Free;
  end;
end;

Этот код получит точно такое же растровое изображение, которое было помещено в ImageList;

Чтобы скопировать один ImageList в другой без потерь, мы можем использовать копирование с потоками:

procedure TbtkImageList.Assign(Source: TPersistent);
var
  IL: TCustomImageList;
  BIL: TbtkImageList;
var
  st: TMemoryStream;
begin
  st := TMemoryStream.Create;
  try
    st.WriteComponent(TbtkImageList(Source));
    st.Seek(0, soFromBeginning);
    st.ReadComponent(Self);
  finally
    st.Free;
  end;
end;
person user1443993    schedule 17.03.2014