A: Here is the idea in short form:
VAR
Pic : TPicture;
TI : TIcon;
BEGIN
...
TI := TIcon.Create;
TI.Handle := ExtractIcon(HInstance, FileNameBuf, 0);
Pic := TPicture.Create;
Pic.Icon := TI;
Image1.Picture := Pic; {TImage}
BitBtn1.Glyph := TBitmap.Create;
WITH BitBtn1.Glyph DO
BEGIN
width := TI.Width;
Height := TI.Height;
Canvas.Draw(0, 0, Pic.Icon);
END;
....
END;
I added a TBitBtn and a TImage to the Form. You will see that
TImage looks OK but sometimes not the TBitBtn.
This is due too that Delphi's Glyph-drawing code checks the lower Left
Corner pixel and uses that as the transparent color. I don't know why they
changed that during development cycle. But of course you can change that
pixel yourself.
Here is the idea in long form. It does much more.
This code take a 32x32 icon and runs it through 2 passes. First it makes it a 16x32 bitmap. The second takes it to 16x16. In the reduction I take special care of edges (often black or a single pixel width color that needs to be maintained) and patterns. By patterns I am referring to dithering by alternating 2 colors to give a third. An example of this is using dark yellow and lite gray to give the color of a folder. These patterns are maintained even after the reduction. I also give special weight to certain colors in the seperate passes. If none of these conditions apply I averaging.
This procedure will give almost but not exactly the same results as MS in Win95. By the way This is the same technique they use I found out later. Also of interest is the fact that this is rather slow so in my Win95 TaskBar replacement (that sure could use Delphi32 by the way so as to by mutithreaded and allow me to do the last thing that I can't do in 16 bit land, that is implement the notification area) I cache the 16x16 bitmaps.
procedure TTask.scaleaicon(i:integer);
var
m,n,p,q
:integer;
ibitmap,ibitmap1,
oldbitmap,oldbitmap1,
oldbitmap2
:hbitmap;
icolor
:tcolorref;
pc
:array[1..4] of tcolorref;
r,g,b
:byte;
memdc,memdc1,memdc2 :hdc;
isedge,dither
:boolean;
begin
memdc:=createcompatibledc(canvas.handle);
memdc1:=createcompatibledc(canvas.handle);
memdc2:=createcompatibledc(canvas.handle);
ibitmap:=createcompatiblebitmap(canvas.handle,32,32);
ibitmap1:=createcompatiblebitmap(canvas.handle,16,32);
oldbitmap:=selectobject(memdc,ibitmap);
oldbitmap1:=selectobject(memdc1,ibitmap1);
oldbitmap2:=selectobject(memdc2,lapp[i].ibitmap);
selectobject(memdc,getstockobject(ltgray_brush));
selectobject(memdc1,getstockobject(ltgray_brush));
selectobject(memdc2,getstockobject(ltgray_brush));
patblt(memdc,0,0,32,32,patcopy);
patblt(memdc1,0,0,16,32,patcopy);
patblt(memdc2,0,0,16,16,patcopy);
drawicon(memdc,0,0,apicon);
m:=0;p:=0;
n:=0;q:=0;
while m<32 do
begin
while n<32 do
begin
dither:=false;
icolor:=getpixel(memdc,n,m);
pc[1]:=icolor;
icolor:=getpixel(memdc,n+1,m);
pc[2]:=icolor;
if (n>0) and (n<30) then
begin
icolor:=getpixel(memdc,n+2,m);
pc[3]:=icolor;
icolor:=getpixel(memdc,n+3,m);
pc[4]:=icolor;
if (pc[1]=pc[3]) and (pc[2]=pc[4])
then
begin
dither:=true;
setpixel(memdc1,q,p,pc[1]);
setpixel(memdc1,q+1,p,pc[2]);
n:=n+4;
q:=q+2;
end;
end;
if not dither then
begin
isedge:=false;
if (n=0) then
begin
if (pc[1]=0)
or (pc[2]=0) then
begin
isedge:=true;
setpixel(memdc1,q,p,0);
n:=n+2;
q:=q+1;
end else
if (pc[1]=8421504)
or (pc[2]=8421504) then
begin
isedge:=true;
setpixel(memdc1,q,p,8421504);
n:=n+2;
q:=q+1;
end;
end;
if (n=30) then
begin
if (pc[1]=0)
or (pc[2]=0) then
begin
isedge:=true;
setpixel(memdc1,q,p,0);
n:=n+2;
q:=q+1;
end else
if (pc[1]=8421504)
or (pc[2]=8421504) then
begin
isedge:=true;
setpixel(memdc1,q,p,8421504);
n:=n+2;
q:=q+1;
end;
end;
if not isedge then
begin
if ((pc[1]=12632256)
and (pc[2]=8421504)) or ((pc[1]=8421504) and (pc[2]=12632256)) then
begin
r:=128;g:=128;b:=128;
end else
if ((pc[1]=16777215)
and (pc[2]=12632256)) or ((pc[1]=12632256) and (pc[2]=16777215)) then
begin
r:=192;g:=192;b:=192;
end else
if (pc[1]=0)
or (pc[2]=0) then
begin
r:=0;g:=0;b:=0;
end else
begin
r:=byte(round((getrvalue(pc[1])+getrvalue(pc[2]))/2));
g:=byte(round((getgvalue(pc[1])+getgvalue(pc[2]))/2));
b:=byte(round((getbvalue(pc[1])+getbvalue(pc[2]))/2));
end;
setpixel(memdc1,q,p,rgb(r,g,b));
n:=n+2;
q:=q+1;
end;
end;
end;
m:=m+1;
p:=p+1;
n:=0;
q:=0;
end;
m:=0;p:=0;
n:=0;q:=0;
while n<16 do
begin
while m<32 do
begin
dither:=false;
icolor:=getpixel(memdc1,n,m);
pc[1]:=icolor;
icolor:=getpixel(memdc1,n,m+1);
pc[2]:=icolor;
if (m>0) and (m<30) then
begin
icolor:=getpixel(memdc1,n,m+2);
pc[3]:=icolor;
icolor:=getpixel(memdc1,n,m+3);
pc[4]:=icolor;
if (pc[1]=pc[3]) and (pc[2]=pc[4])
then
begin
dither:=true;
setpixel(memdc2,q,p,pc[1]);
setpixel(memdc2,q,p+1,pc[2]);
m:=m+4;
p:=p+2;
end;
end;
if not dither then
begin
isedge:=false;
if (m=0) then
begin
if (pc[1]=0)
or (pc[2]=0) then
begin
isedge:=true;
setpixel(memdc2,q,p,0);
m:=m+2;
p:=p+1;
end else
if (pc[1]=8421504)
or (pc[2]=8421504) then
begin
isedge:=true;
setpixel(memdc2,q,p,8421504);
m:=m+2;
p:=p+1;
end;
end;
if (m=30) then
begin
if (pc[1]=0)
or (pc[2]=0) then
begin
isedge:=true;
setpixel(memdc2,q,p,0);
m:=m+2;
p:=p+1;
end else
if (pc[1]=8421504)
or (pc[2]=8421504) then
begin
isedge:=true;
setpixel(memdc2,q,p,8421504);
m:=m+2;
p:=p+1;
end;
end;
if not isedge then
begin
if ((pc[1]=12632256)
and (pc[2]=8421504)) or ((pc[1]=8421504) and (pc[2]=12632256)) then
begin
r:=128;g:=128;b:=128;
end else
if ((pc[1]=16777215)
and (pc[2]=12632256)) or ((pc[1]=12632256) and (pc[2]=16777215)) then
begin
r:=192;g:=192;b:=192;
end else
if ((pc[1]=0)
and (pc[2]=8421504)) or ((pc[1]=8421504) and (pc[2]=0)) then
begin
r:=128;g:=128;b:=128;
end else
if (pc[1]=8421504)
or (pc[2]=8421504) then
begin
r:=128;g:=128;b:=128;
end else
begin
r:=byte(round((getrvalue(pc[1])+getrvalue(pc[2]))/2));
g:=byte(round((getgvalue(pc[1])+getgvalue(pc[2]))/2));
b:=byte(round((getbvalue(pc[1])+getbvalue(pc[2]))/2));
end;
setpixel(memdc2,q,p,rgb(r,g,b));
m:=m+2;
p:=p+1;
end;
end;
end;
n:=n+1;
q:=q+1;
m:=0;
p:=0;
end;
selectobject(memdc,oldbitmap);
selectobject(memdc1,oldbitmap1);
selectobject(memdc2,oldbitmap2);
deleteobject(ibitmap);
deleteobject(ibitmap1);
deletedc(memdc);
deletedc(memdc1);
deletedc(memdc2);
end;