Главная » Delphi » Преобразование BitMap в Icon

0

Как мы видим, иконка (Icon)— это совсем не просто картинка 32×32 пиксела. По этой причине преобразование BitMap в Icon и обратно простым копированием невозможно. А как же быть, если мы страстно хотим создать иконку динамически, прямо при выполнении программы? Придется изворачиваться. Сейчас мы соорудим демонстрационную программу (доводить до полноценного приложения не будем), которая загружает произвольную картинку в формате JPEG или BMP, преобразует ее в иконку и сохраняет полученный ICO-файл. Заодно по ходу дела будут проиллюстрированы многие приемы работы с картинками в Delphi. В качестве пробного камня используем полноцветный женский портрет размером 800×600 пикселов на белом поле (я его заимствовал из сборника экранных обоев), логотип Apple в базовых цветах и фото бабочки, палитра которой изначально также была близка к базовой. Формат всех исходных файлов JPEG (файлы oboi359.jpg, apple.jpg и butterflyl.jpg находятся на диске в папке GlavalOM).

Создадим новый проект (папка GlavalOM), назовем его Iconka, разместим на форме компонент Panel, оставив справа свободное поле, покрасим его (свойство Color) в черный цвет и на него поставим компонент image— в точности так, как мы это делали в SiideShow в глсюе 2. У компонента image установим в True свойства stretch и Proportional. На форму добавим компонент Open- Dialog, у которого установим фильтр по файлам с изображениями JPEG и BMP (в правое поле в окне OpenDialogl.Filtcr надо вписать *.jpg; *.bmp). Собственно, формат BMP нам в этом примере в качестве исходного не пригодится, но в принципе не помешает, а реализовать его загрузку очень просто, т. к. JPEG все равно придется переводить в BMP для последующих манипуляций. Объявляем следующие переменные:

var

Formi: TForml;

Jpglm: TJpeglmage; /объявляем переменную типа JPEGj

Bniplm, IcoBmp, XORmask, ANDmask: TBitMap; {переменные типа BitMap)

IcoIco:TIcon; {переменная типа иконка I

RectS,RectT:TRect;

IсоInfo : Tlconlnfo;

st,filename:string;

Сразу, не особенно разбираясь, соорудим процедуру уничтожения всех экземпляров классов при закрытии программы (кроме jpgim, которую мы будем уничтожать сразу после использования):

procedure TForml.FormClcse(Sender: TObject; var Action: TCloseAction);

begin {все уничтожаем}

try

ANDMask.Destroy; XORMask.Destroy; Icoanp.Destroy; Icolco.Destroy; Smplm.Destroy; except end; end;

Далее создадим процедуру инициализации диалога открытия файла при запуске программы, с тем. чтобы он открывался на текущем каталоге:

procedure TForml.FormCreate(Sender: TObject}; begin

chDir(ExtractFileDir(Application.ExeName));

OpenDialogl.InitialDir:=ExtractFileDir(Application.ExeName);

end;

Поставим на форму кнопку Buttoni с заголовком Load и напишем следующий обработчик для щелчка на ней:

procedure TForml.ButtonlClick(Sender: TObject); begin (Load – загрузка} Bmplm := TBitMap.Create; {создаем экземпляр объекта типа BitMap} If OpenDialogl.Execute then filename:=OpenDialogl.filename else exit; try

If ExtractFileExt(filename)=’.jpg’ then begin

Jpglm := TJpeglmage.Create;

{создаем экземпляр объекта типа JPEG} Jpglm.LoadFromFile(filename) ;

{в JPEG загружаем изображение с диска} Bmplm.Assign(Jpglm); {в BitMap загружаем изображение из JPEG} Jpglm.Destroy; {уничтожаем объект JPEG} end;

If ExtractFileExt(filename)=’.bmp’ then Bmplm.LoadFromFile(filename);

{в BMP загружаем изображение с диска} except exit; end;

Imagel.Picture.Assign(Bmplm); (выводим BitMap на экран} end;

Пробовать начнем с самого сложного образца — женского портрета. Вот результат загрузки его в окно Imagel (рис. 10.3).

Заметим, что компонент image можно было бы и не устанавливать, а рисовать прямо на канве формы или любого другого компонента, просто с ним в данном случае работать удобнее (но, как мы увидим позже, иногда дело идет лучше, если использовать другие компоненты).

Для начала нам надо решить проблему, как преобразовать прямоугольную картинку в квадратную без ее искажения, т. с. осуществить операцию cropping (букв, "подстригание"), известную по любому графическому редактору. Разумеется, если изначальная картинка квадратная и близка к тому, то этого делать не нужно (и, например, для логотипа Apple эту операцию следует пропустить). Несложно реализовать ручное указание области, которую нужно сохранить при данной операции, но я предоставляю читателю самому разобраться с этим делом, а здесь реализую автоматическое выделение квадрата по центру картинки, в зависимости от того, по какому измерению картинка больше — по высоте или по ширине. Поместим на форму кнопку Button2 (Crop) и напишем для нее следующий обработчик: procedure TForml. But. tori2ClicSc (Sender: TObject);

var x, у: integer; {Crop – делаем картинку квадратной}

begin

if BmpIm.Width>BmpIm.Height then {гели больше по ширине) begin

х: = (BmpIm.Width-Bmp.1m.Height) div 2; Iрасст. от левого края) RectS:=Rect(х,0,x+BmpIm.Height,Bmplm.Height);

Iисходное папе по центру картинки) RectT:=Rect(0,0,Bmplm.Height,Bmplm.Height); {поло, куда копировать) end else {если больше по высоте) begin

х: =(Bmplm.Height-Bmplm.Width) div 2; {расст. от верхнего края) RectS:=Rect(0,х,Bmplm.Width,x+Bmplm.Width);

{исходное поле по центру картинки) RectT:=Rect(0,0,xfBmpT.m.Width,Bmplm.Width) ; {поле, куда копировать)

end;

Bmplm. Canvas. CopyMode: =cm3rсСору ;

{режим копирования – на всякий случай/ Bmplm.Canvas. CopyRect. (RectT, Bmplm. Canvas, RectS); I копируем) Bmplm.Width:=BmpIm.Height; {усекаем до квадрата) Imagel.Picture.Assign(Bmplm); {вывозим BitMap на экран) end;

Рис- 10.3. Образец для преобразования BitMap а иконку

Далее нам нужен BitMap размером 32×32, стандартный размер иконки. Можно все сделать в исходном BitMap, но мы его сохраним на всякий случай в неприкосновенности, и скопируем изображение в новый BitMap icoBmp. Поставим на форму еще одну кнопку Button3 (Resize) и напишем для нее такой обработчик:

procedure TForml.Button3Click(Sender: TObject); begin (Resise уменьшаем до размера 32×32 f IcoBmp := TBitMap.Create;

(создаем экземпляр объекта тила BitMap} IcoBmp.Height:=32; (новая картинка 32×32) IcoBmp.Width:=32;

RectT:=Rect(0,0,32,32); (поле, куда копировать) IcoBmp.Canvas.StretchDraw(RectT,Bmplm);

(копируем с усечением размеров) Imagel. Proportional’.-False; (демонстрировать будемI Imagel.Stretch:=False; (в натуральном виде) Imagel. Picture. Assign (IcoBmp); /’вызолим BiШар на экран) st:=ExtractFilename(filename); (меняем имя файла) filename: =’0’+s t;

(чтобы не путать с исходным, папку можно не указывать) IcoBmp.SaveToFile(ChangeFileExt(filename,’.bmp’)); end;

Заметки на полях

Обратите внимание на один нюанс в обращении с областями типа TRcct и параметрами width и Height BitMap. В качестве конечной точки по X и по Y здесь указывается величина, отстоящая от начальной на величину общего количества точек (а не номер конечной точки, если считать начальную за нулевую). То есть верхняя граница будет на единицу больше, чем это было бы при указании границы массива. Далее, когда мы будем иметь дело с массивом Pixels канвы, там те же границы будут указываться нормально: (0. .31), т. е. всего 32 элемента. Эту разницу легко понять из определений массива и прямоугольника из точек: массив massiv [0. .1,0. Л] имеет четыре элемента, а прямоугольник rect (0,1,0,1) — один-единственный!

Для контроля мы выводим полученный BitMap в файл с именем исходного, но начинающимся с символа "0". На экран мы выводим картинку в натуральном, а не растянутом виде, чтобы убедиться, что изображение действительно уменьшилось. Далее мы хотим посмотреть, как это будет выглядеть в растянутом виде— ведь именно IcoBmp у нас будет представлять потом маску xoRMask. Для этого поставим на форму еще одну кнопку Buttons (Stretch) и напишем для нее такой обработчик:

procedure TForml .Button’lClick (Sender: TObject); begin (Stretch – растягиваем для наглядности! Imagel.Proportional:=True; Imagel.Stretch:=True; Imagel.Repaint; {перерисовать заново) end;

Результат демонстрации будущей иконки в увеличенном виде показан на рис. 10.4.

Рис. 10.4. Будущая иконка 32×32 в увеличенном виде

Теперь займемся конструированием ANDMask. Для этого придется создать монохромный битмэп и скопировать в него наше изображение. Добавим еще одну кнопку Buttons (ANDMask) и вот такой обработчик для нее:

procedure TForml.ButtonbClick(Sender: TObject);

begin (Создаем маску And)

ANDMask := TBitMap.Create;

ANDMask.Assign(IcoBmp);

ANDMask.Monochrome := true; {монохромную!

Imagel.Picture.Assign(AndMask); (вывода AND на экран!

end;

Вот что мы увидим на экране— рис. Ю.5. В принципе нам сейчас не очень важно, какая именно маска получится — рисунок в ANDMask важен лишь при формировании "прозрачного" цвета, в остальных случаях, как мы говорили, можно сделать просто черный прямоугольник, а прозрачностью мы займемся позднее.

Рис. 10.6. Маска ANDMask в увеличенном виде

Теперь можно заняться, наконец, собственно иконкой. Создавать мы ее будем с помощью функции API Createiconindirect, которая требует заполнения структуры iconinfo (устроенной много проще, чем структура bitmapinfo). Поставим на форму еще одну кнопку Buttons (далеко не последнюю, как вы увидите) и создадим обработчик щелчка для нее. Здесь я для наглядности скопировал картинку 32×32 из icoBmp в новый BitMap xoRMask, разумеется, можно обойтись и без этих промежуточных преобразований (и даже вообще использовать изначальный Bmpim, если его не жалко):

procedure TForml.Button6Click(Sender: TObject); begin (Icon – превращаем в иконку} XORMask:= TBitMap.Create;

XORMask.Assign(IcoBmp); /в качестве XOR-маски используем наш BMP)

Icolco := TIcon.Create;

Icolnfo.flcon := True;

Icolnfo.xHotspot := 0;

Icolnfo.yHotspot := 0;

Icolnfo.hbmMask := ANDMask.Handle;

Icolnfo.hbmColor := XORMask.Handle;

Icolco.Handle := Createiconindirect(Icolnfo);

Icolco.SaveToFile(ChangeFileExt(OpenDialogl.filename,’.ico’));

Imagel.Picture.LoadFromFile

(ChangeFileExt(OpenDialogl.filename, ‘.ico’)); (выводим иконку на экран)

and;

В качестве комментария к параметру icoinfo.ficon я привел строку из официального описания этой структуры: "величина True специфицирует иконку". Два следующих параметра имеют значение, если мы создаем курсор, а не иконку. Имейте это в виду, если захотите создавать свои курсоры, они создаются в точности так же, как и иконка. Лично мне никогда этого делать не приходилось, потому что, на мой взгляд, всякая самодеятельность в этом отношении может только раздражать пользователей (и, например, в фирменных графических редакторах раздражает безумно). В 99% случаев достаточно обычного курсора в виде стрелки, а для оставшегося одного процента, когда это действительно необходимо, например в браузерах при указании на ссылку, Windows предлагает вполне приличный набор готовых.

Но результат, появившийся в imagei после выполнения этой процедуры, нас обескуражит: иконка получится черно-белой (поэтому мы кнопку Buttone назвали Icon B&W). Проверьте полученный файл с именем oboi350.ico — в нем также окажется черно-белая иконка. Для того чтобы рассмотреть подробнее, что именно получилось, нам следует, во-первых, перезагрузить иконку из полученного файла, во-вторых, превратить ее в BitMap — при простом отображении иконки на канве она не растягивается, а демонстрируется только в оригинальном размере 32×32, изображение иконки на канве не зависит от свойства stretch. Поставим на форму кнопку Button7 (Icon Stretch) и для нее напишем такой обработчик:

procedure TForml..Bu»;ton7Click (Sender: TObjec.t);

begin I Icon Stretch - растягиваем готовую иконку!

IcoBmp.Destroy; (все заново}

IcoBmp:-TBitMap.Create;

Icolco.Destroy;

Icolco := TIcon.Create;

Icolco.LoadFromFile(ChangeFileExt(OpenDialogl.filename, ‘.ico’)); IcoBmp.Width:=IcoIco.Width; IcoBmp.Height:=IcoIco.Height;

IcoBmp.Canvas.Draw(0,0,Icolco); (преобразуем в BitMap} Imagei.Picture.Assign(IcoBmp);(выводим ICO на экран} end;

При рассмотрении в увеличенном виде окажется, что отдельные цветные пятна на женском портрете все же имеются. Это связано с тем, что исходное изображение было TrueColor, а в случае иконок Delphi разбирает только 16 базовых цветов, которых у нас в данном случае почти нет. Если же мы поэкспериментируем с другими примерами, то увидим, что они отображаются относительно нормально — логотип apple.jpg, например, вообще перенесется в иконку практически один к одному, даже с намеками на тени, из-за того.

что он практически из одних базовых цветов и состоит. Есть два пути решения этой проблемы — один заключается в том, чтобы самостоятельно, полностью с нуля, создать и записать файл иконки, использовав там то количество цветов, какое нам нужно. Неплохое описание подобного процесса имеется в базе FAQ по Delphi [24]. Этот путь вполне нормален для DOS (и автор в свое время создавал такие файлы, написав вполне работоспособный, хотя и не очень удобный DOS-редактор иконок), но мы же живем в эпоху Windows!

Попробуем просто сделать так, чтобы в нашей иконке содержались одни базовые цвета, т. е. реализуем операцию редукции цветов. Причем наша задача— именно свести палитру к базовой, а не просто сократить количество цветов до 16, как это делают графические редакторы по умолчанию. Преобразование исходной картинки в 16-цветную в каком-либо редакторе нам не поможет, потому что к базовому набору цветов палитру если и удастся свести, то результат будет весьма плачевный (см. в папке с проектом эксперименты с файлом oboil6col.bmp, полученным из нашего женского портрета редукцией цветов к базовым через Photoshop). Простое приравнивание палитры иконки палитре исходной XOR-маски также не помогает, даже если исходный файл 16-цветный — скорее всего, на исходную палитру загружаемого изображения переменная типа BitMap в Delphi просто не обращает внимания, всегда формируя 24-битное изображение. Можно попробовать создать отдельно только XOR-маску вручную (через функции API или непосредственно), но этот способ все равно не был бы универсальным, т. к. в формате JPEG вообще может присутствовать только 24-битное представление цвета, и огромное количество подготовительной работы по сведению их к 16 цвет ам и пересохранению в формате BMP обессмыслило бы всю затею автоматического формирования иконки.

Среди методов класса TBitMap есть процедура присвоения глубины цвета, например, МОЖНО попробовать записать XORMask. PixelFormat:=pf<]bit. Но ЭТО совсем не процедура редукции — если попробовать присвоить это значение после того, как выполнена операция Assign, то вам укажут на ошибку, а до того— естественно, это никак не повлияет на результат. Спасибо, как говорится, и на том, что свойство Monochrome нормально работает (хотя создать маску AND ничего не стоит и вручную, все равно для "прозрачного" цвета ее придется править). Нам ничего не остается, кроме как придумать алгоритм редукции TrueColor к 16 базовым цветам самим.

Простой способ редуцировать трехбайтное представление цвета к четырехбитовому мне не известен и вряд ли он существует— когда выбирались базовые цвета для VGA-режима, думали, естественно, не об удобствах преобразования, а о том, чтобы они как можно шире охватывали реальный спектр. Однозначного алгоритма редуцирования разрядности цвета нет вообще — в продвинутых графических редакторах вам всегда предлагают выбор. Поэтому в приложениях, которые могут выполняться на различных платформах (например, для HTML-страниц), даже рекомендовано использовать конкретные 216 "безопасных" оттенков, которые однозначно отображаются при преобразованиях цветов по цепочке 24-18-8 бит (см. http://html.manual.ru/book /info/basecolors.php). Если кто-то из читателей додумается, как это преобразование выполнить наиболее просто и адекватно, пусть напишет. Грамотным решением было бы использование приемов аналитической геометрии для разбиения цветового куба (трехмерной пространственной области, по осям которой отложены значения трех спектральных составляющих от 0 до 255) на 16 областей, близких к базовым цветам. Однако реализация этого алгоритма слишком сложна, и к тому же предполагает использование эвристических данных о восприятии цветов, чтобы имело смысл разбирать его в рамках данной книги.

Здесь мы сделаем это "лобовым методом", без учета зрительного восприятия и точного соответствия оттенков. Конечных вариантов всего 16, все они перечислены в табл. 10.1 и содержат, как мы видим, в основном три варианта значений байтов, равные $FF, $80 и $00, причем варианты совместного присутствия значений $FF и $80 не встречаются, зато имеется отличный от указанных вариант со светло-серым цветом. Последним мы для простоты пожертвуем (он у нас будет воспроизводиться как белый, и это несколько подпортит всю картинку, как мы увидим далее). Алгоритм реализуем в два этапа. На первом поделим все варианты цветов на "светлые" и "темные" по условию: если хотя бы одна из составляющих больше 128, то этот цвет— "светлый", в противном случае — "темный". На втором этапе проанализируем отдельно каждую составляющую. Если общий цвет был классифицирован как "темный", то она может принимать значения в диапазоне 0—128. Разобьем этот диапазон ровно пополам, и будем составляющей присваивать значение $80, если она больше половины, и 0, если меньше. Для "светлых" тонов отдельные составляющие могут лежать в диапазоне 0—255. Также разобьем этот диапазон пополам, и будем присваивать составляющей значение $FF, если она больше половины, и 0, если меньше. Так мы исключим сочетания $80 и $FF, в противном случае 12 вариантов (всего 27 вариантов, нас устраивает 15) пришлось бы отсеивать по отдельности.

Простой доступ к цвету каждого пиксела (т. е. к его значению в 24-битной палитре), по счастью, у нас имеется — это массив pixels канвы (манипуляциями с этим массивом, кстати, можно заменить большинство штатных методов канвы, только выполняться эти операции будут намного дольше оригинальных, основанных на прямом обращении к видеопамяти). Поставим на форму кнопку Buttons (XOR Color) и напишем такую процедуру:

procedure TForml.ButtonSClick(Sender: TObject); var xcol,x,у:integer; (XOR Color меняем цвета) var colR,colG,ColB:byte; begin

for x:=0 to 31 do

for y:=0 to 31 do {по всему массиву точек) begin

xcol:=XORMask.Canvas.Pixels[x,y]; colR:=Lo(xcol); colG:=Lo(xcol ehr 8);

colB:=«Lo (xcol ehr 16); (RGB-составляющие I if (colR>$80) or (colG>$80) or (colB>$80) then begin {светлый цвет) if colR>$80 then colR:=$FF else colR:=0; if colG>580 then colG:=$FF else colG:=0; if colB>$80 then colB:=$FF else colB:=0; end else {темный цвет) begin

if colR>$40 then colR:=$80 else colR:=0; if colG>$40 then colG:=$80 else colG:=0; if colB>$40 then colB:=$80 else colB:=0;

end;

xcol:=colR+256*colG+65536*colB; (собираем цвет обратно) XORMask.Canvas.Pixels[x,yl:=xcol; end;

Imagel.Picture.Assign (XORMask); (выводим XOR на экран) end;

Результат (рис. 10.6) в данном случае будет, прямо скажем, "не очень" — хотя и несколько лучше, чем при экспериментах с Photoshop (сравните иконки в файлах oboi350.ico и oboil6coI.ico). Читатели самостоятельно могут поэкспериментировать с указанным алгоритмом, с целью улучшить качество изображения (например, хотя бы ввести светло-серый). А вот с другими образцами все куда лучше, хотя с ними и изначально было неплохо (рис. 10.7)— что есть следствие наличия нужных или близких цветов в оригинальном изображении. Для логотипа Apple, например, всего лишь уберется тень, что даже лучше при последующем преобразовании в "прозрачную" иконку. Для большего понимания, что происходит с масками при их взаимодействии, сравните все увеличенные результаты для масок AND, XOR и самой иконки для образца с логотипом Apple.

Но никто и не утверждал, что любой JPEG можно автоматически превратить в иконку и при этом сразу получить идеальный результат. Для достижения

Рис. 10.6. Результет редукции цветов для женского портрете

 

Рис. 10-7. Иконка бвбочки в натуральном виде (а) и после редукции цветов (б)

абсолютно адекватного результата недостаточно даже ручного редактирования, получить его можно только, если использовать иконки TrueColor. Но и тогда для получения более-менее приемлемого результата ручное вмешательство потребуется, и для этого созданную нами программу стоит превратить в нормальный редактор иконок. Это теперь несложно, причем с реализацией встречающейся достаточно редко функции превращения в иконку произвольного изображения. Читатель уже вполне может самостоятельно с этим справиться.

Для того чтобы переделать иконку окончательно, поставим еще одну кнопку Buttons (Icon) и напишем такой обработчик:

procedure TForml.Button9Click{Sender: TObj ect);

begin {Icon создаем иконку заново)

Icolco.Destroy; (будем создавать заново)

Icolco := TIcon.Create;

Icolnfo.fIcon := True;

Icolnfo.xHotspot := 0;

Icolnfo.yHotspot := 0;

Icolnfo.hbmMask ANDMask,Handle;

Icolnfo.htsnColor := XORMask.Handle;

IcoIco.Handle := Createlconlndirect(Icolnfo);

Icolco.SaveToFile(ChangeFileExt(OpenDialogl.filename, ‘.ico’)) ;

Imagel.Picture.LoadFromFile

(ChangeFileExt(OpenDialogl.filename,’.ico’)); (выводим иконку на экран)

end;

Для того чтобы завершить тему создания иконок, нужно ответить на вопрос — как реализовать "прозрачный" цвет? Так как мы имеем все маски, то проще всего сделать это вручную, преобразованием пикселов. Мы покажем процедуру опять же на примере автоматического преобразования — попробуем осуществить замену заданного цвета на "прозрачный".

Чтобы не возиться с CoiorBox или другими вариантами "цветовых" компонентов в этой пародии на настоящее приложение, которое мы создаем, для задания цвета поставим на форму компонент CoiorDialog и только заменим у него свойство Color на ciwhite. Решение очень неаккуратное, но для нас здесь, как временное решение, сойдет— мы хотим лишь показать, как и что делать в соответствующей ситуации. Поставим на форму очередную кнопку Buttonio (Icon) и вот как будет выглядеть обработчик для нее:

procedure TForml.ButtonlOClick(Sender: TObject); var x,у:integer;

begin {прозрачный цвет) if ColorDialog1.Execute then begin for x:=0 to 31 do

for y:=0 to 31 do {по всему массиву точек}

if XORMask.Canvas.Pixels[x,y]= ColorDialogl.Color then

begin

XORMask.Canvas.Pixels[x,y]:=0; ANDMask.Canvas.Pixels[x,у]:=clWhite; end;

Icolco.Destroy; {будем создавать заново} Icolco := TIcon.Create; Icolnfo.flcon := True; Icolnfo.xHotspot := 0; Icolnfo.yHotspot := 0; Icolnfo.hbmMasк ANDMask.Handle; Icolnfo.hbmColor := XORMask.Handle; Icolco.Handle : = Createiconindirect(Icolnfo); Icolco.SaveToFile(ChangeFileExt(OpenDialogl.filename,1.ico’)); Imagel.Picture.LoadFromFile(ChangeFileExt (OpenDialogl.filename, ‘.ico’));

{выводш иконку на экран}

end; end;

Чтобы понять, что именно тут делается, обратитесь к описанию принципа совместной работы масок AND и XOR ранее. Осталось только показать, как лихо можно подменить иконку самого приложения прямо на ходу. Поставим на форму последнюю кнопку Buttonli (USE). Обработчик будет состоять всего из одной строки:

procedure TForml.ButtonllClick(Sender: TObject); begin {USE – применить иконку к приложению I

Application.Icon:=IcoIco; end;

После нажатия на кнопку USE текущая иконка, которая содержится в icolco, сразу появится в заголовке формы.

Заметки на полях

Читатель вправе задать вопрос — а почему для задания "прозрачного" цвета нельзя воспользоваться удобным механизмом, который предлагают свойства TransparentColor и TransparentMode класса TBitMap? Дело В том, что они работают только при отображении BitMap на экране и никак не сказываются на представлении карты битов в памяти, т. е. при сохрвнении в файл, копировании в другой BitMap или переносе в иконку эти свойстве "пропадают". Попробуйте внести в самую первую процедуру по нажатию But сот следующие строки (их нвдо вставить непосредственно перед звгрузкой квртинки в imagei операцией Assign):

Bmplm.TransparentColor:=clWhite; Imagei.Transparent:=True;

При загрузке женского портрета белый фон станет "прозрачным" (выглядеть это будет довольно неаккуратно, т. к. отдельные области фона, нв первый взгляд тоже белые, на самом деле таковыми не являются). Но уже на третьем шаге (при переводе в размер 32×32) прозрачность "кудв-то" исчезнет. Звметим, что отсутствие функции указания диапазона цветов сильно ограничивает возможности механизма, фвктически он применим только к картинкам с однородными по цвету полями (даже логотип Apple из-за нвличия теней не будет отобрвжать- ся как надо). Если вы хотите отображать с эффектом прозрачности произвольные картинки с широкой гвммой цветов, то вам либо придется кропотливо заменять нужные цвете (например, все светлые) на какой-то один, который потом объявляется "прозрачным", либо не миновать "ручной" процедуры создания масок по типу, квк мы это делали для иконки. Создавать саму иконку, конечно, не нужно, маски AND и XOR (произвольного размера) комбинируются с фоном также вручную с использованием функции API BitBit или даже проще — путем задвния свойства CopyMode при использовании процедуры CopyRect.

Дадим здесь и пару советов, как прввильно пользоваться механизмом отображения "прозрачных" BitMap. Вопреки распространенному мнению, если вы задаете свой собственный цвет, который должен стать прозрачным, параметр TransparentMode специально устанавливать в значение rnrixed не надо — это происходит автоматически при установке свойства TransparentCoior. Единственное, когда требуется установка TransparentMode — когда вы отказываетесь от собственного цвета, вы звдаете свойству знвчение tmAuto, и цвет будет определяться левым нижним пикселом изображения (именно нижним, хотя в фирменной справке все запутали, указав на два возможных варианта — в Windows, как мы знвем, формат BMP начинается с нижней строки). В этом случае, нвоборот, устанавливать свойство TransparentCoior уже нельзя. Кроме этого, чтобы отображение "прозрачного" цвета прошло успешно, надо не эа- быввть устанавливать свойство Transparent соответствующего компонента в True (у нас это Imagei).

Если стоит задача изменить готовую иконку, то ее надо загрузить из файла, как мы делали раньше. Получить доступ к маске XOR можно также описанным ранее способом через процедуру Draw канвы любого BitMap, а вот с AND-маской придется повозиться. Сначала нужно получить структуру

iconinfo:

Icolnfo : TIconlnfo; Icolco : TIcon;

Getlconinfo(Icolco.Handle,Icolnfo);

В результате в icoinfo окажется структура icon info нашей иконки, а в ней, как мы уже знаем, содержатся дескрипторы масок под названиями tibmMe.sk (маска AND) и hbmcolor (маска XOR). Далее необходимо извлечь информацию ПО НУЖНОМУ Дескриптору, причем ПрОСТО Приравнять Bmplm. Handle: = icoinfo.hbmMssk не выйдет, надо действовать через глобальную кучу. Так что в самом простом случае при изменениях готовой иконки проще будет сформировать AND-маску заново— кажется, именно так и поступал Image Editor старых версий Delphi.

В целом наша программа, как готовое приложение, разумеется, никуда не годится — если сразу после запуска случайно нажать на любую из кнопок, кроме Load, получите кучу претензий за обращение к несуществующим объектам. Но мы ее здесь создавали только в качестве иллюстрации того, как вообще надо обращаться с иконками и BitMap.

Источник: Ревнч Ю. В.  Нестандартные приемы программирования на Delphi. — СПб.: БХВ-Петербург, 2005. — 560 е.: ил.

По теме:

  • Комментарии