昨天在使用FreeImage的时候发现FreeImage对ICON的处理有问题,32位的帧读出来的背景居然是黑的。我猜应该是32位没有And的Mask数据。而它按照24位以下的处理方式把Alpha值填成255了。
只能自己动手写代码,也不复杂,算上把Windows单元抽出来声明的结构体,也就300行。经测试可以在Win32,Win64,Android,FMX for Linux上可以正常使用。
如此的简单,就不上传工程了,直接贴代码就是了。
unit FMX.Images.icon;
{
wr960204武稀松
2017.4.18
FMX读取ICO,ICON文件各个帧到TBitmap的。
经测试支持Win32, Win64,Android,FMX for Linux
}
interface
uses
System.Types, // Winapi.Windows,
System.Classes, System.sysutils, FMX.Graphics,
System.Generics.Collections;
const
PNG_Signature = $0A1A0A0D474E5089;
type
// 从WinAPi.Windows单元拷贝过来的。为了不引用Windows单元,以便跨平台
tagBITMAPINFOHEADER = record
biSize: DWORD;
biWidth: DWORD;
biHeight: DWORD;
biPlanes: Word;
biBitCount: Word;
biCompression: DWORD;
biSizeImage: DWORD;
biXPelsPerMeter: DWORD;
biYPelsPerMeter: DWORD;
biClrUsed: DWORD;
biClrImportant: DWORD;
end;
TBitmapInfoHeader = tagBITMAPINFOHEADER;
BITMAPINFOHEADER = tagBITMAPINFOHEADER;
PRGBTriple = ^TRGBTriple;
tagRGBTRIPLE = packed record
rgbtBlue: Byte;
rgbtGreen: Byte;
rgbtRed: Byte;
end;
TRGBTriple = tagRGBTRIPLE;
RGBTRIPLE = tagRGBTRIPLE;
PRGBQuad = ^TRGBQuad;
tagRGBQUAD = packed record
rgbBlue: Byte;
rgbGreen: Byte;
rgbRed: Byte;
rgbReserved: Byte;
end;
TRGBQuad = tagRGBQUAD;
RGBQUAD = tagRGBQUAD;
TIconDirEntry = packed record
bWidth: Byte;
bHeight: Byte;
bColorCount: Byte;
bReserved: Byte;
wPlanes: Word;
wBitCount: Word;
dwBytesInRes: DWORD;
dwImageOffset: DWORD;
end;
// Icon的结构体
PIconDirEntry = ^TIconDirEntry;
TIconDir = packed record
idReserved: Word;
idType: Word;
idCount: Word;
idEntries: array [0 .. $0] of TIconDirEntry;
end;
PIconDir = ^TIconDir;
TICONIMAGE = packed record
icHeader: BITMAPINFOHEADER; // ptr to header
{
icColors: array [0 .. ColorCount] of RGBQUAD; //
icXOR: array [0 .. bWidth * bHeight] of Byte; //
icAND: array [0 .. bWidth * bHeight / bColorCount] of Byte;
}
end;
TICONIMAGEicColors = packed record
icColors: array [0 .. $FFFF] of RGBQUAD; //
end;
TICONIMAGEicXOR = packed record
icXOR: array [0 .. $FFFF] of Byte; //
end;
TICONIMAGEicAND = packed record
icAND: array [0 .. $FFFF] of Byte;
end;
PICONIMAGE = ^TICONIMAGE;
PTICONIMAGEicColors = ^TICONIMAGEicColors;
PICONIMAGEicXOR = ^TICONIMAGEicXOR;
PICONIMAGEicAND = ^TICONIMAGEicAND;
TBmpList = TObjectList<Tbitmap>;
function LoadIcon(AFileName: string; Abmps: TBmpList): Boolean;
function LoadIconByStream(AStream: TStream; Abmps: TBmpList): Boolean;
function LoadIconByBuf(ABuf: PBYTE; ACount: Integer; Abmps: TBmpList): Boolean;
implementation
function LoadIcon(AFileName: string; Abmps: TBmpList): Boolean;
var
fs: TFileStream;
begin
fs := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
Result := LoadIconByStream(fs, Abmps);
fs.Free;
end;
function LoadIconByStream(AStream: TStream; Abmps: TBmpList): Boolean;
var
bs: TBytes;
ICONDIR: PIconDir;
begin
Result := False;
SetLength(bs, AStream.Size);
AStream.Read(bs[0], Length(bs));
Result := LoadIconByBuf(@bs[0], Length(bs), Abmps);
end;
{$POINTERMATH ON}
function LoadPngFrame(ABuf: PBYTE; ACount: Integer; Abmp: Tbitmap): Boolean;
var
ms: TMemoryStream;
begin
ms := TMemoryStream.Create;
ms.Write(ABuf^, ACount);
ms.Position := 0;
Abmp.LoadFromStream(ms);
ms.Free;
Result := True;
end;
function LoadIconFrame(lpIconDir: PIconDir; lpIconDirEntry: PIconDirEntry;
lpIconImage: PICONIMAGE; Abmp: Tbitmap): Boolean;
var
width, height, realBitsCount: Integer;
x, y: Integer;
hasAndMask: Boolean;
lpColors: PRGBQuad;
lpColorsTriple: PRGBTriple ABSOLUTE lpColors;
lpColors256: PBYTE ABSOLUTE lpColors;
lpXor: PBYTE;
lpAnd: PBYTE;
//
colorMapSize, XorSize, AndSize: Integer;
boundary, shift, shift2, index, bit, mask: Integer;
//
D: TBitmapData;
image: PRGBQuad;
begin
Result := False;
{不能用lpIconDirEntry中的高和宽,教训是有些ICO文件不规范,这里的高和宽是0,
所致最好用lpIconImage^.icHeader中的高和宽
}
width := lpIconImage^.icHeader.biWidth;
height := lpIconImage^.icHeader.biHeight div 2; //高度等于 xor + and mask
realBitsCount := lpIconImage^.icHeader.biBitCount;
hasAndMask := (realBitsCount < 32) and
(height <> lpIconImage^.icHeader.biHeight);
colorMapSize := SizeOf(RGBQUAD) * (1 shl realBitsCount);
if lpIconImage^.icHeader.biSize = 0 then
lpColors := PRGBQuad(UInt64(lpIconImage) + SizeOf(TICONIMAGE) { 40 } )
else
lpColors := PRGBQuad(UInt64(lpIconImage) + lpIconImage^.icHeader.biSize { 40 } );
lpXor := PBYTE(UInt64(lpColors) + colorMapSize);
Abmp.Resize(width, height);
if Abmp.Map(TMapAccess.Write, D) then
begin
case realBitsCount of
32: // 32位色
begin
for y := 0 to height - 1 do
begin
image := D.GetScanline(y);
for x := 0 to width - 1 do
begin
shift := x;
shift2 := (x + (height - y - 1) * width);
{
image[shift].rgbBlue := lpColors[shift2].rgbBlue;
image[shift].rgbGreen := lpColors[shift2].rgbGreen;;
image[shift].rgbRed := lpColors[shift2].rgbRed;
image[shift].rgbReserved := 255;//估计是Free Image这里填写的255.应该用32位色自己的.所以FreeImage拿出来的32位Frame背景居然是黑的
}
image[shift] := lpColors[shift2];
end;
end;
end;
24: // 24位色
begin
for y := 0 to height - 1 do
begin
image := D.GetScanline(y);
for x := 0 to width - 1 do
begin
shift := x;
shift2 := (x + (height - y - 1) * width);
image[shift].rgbBlue := lpColorsTriple[shift2].rgbtBlue;
image[shift].rgbGreen := lpColorsTriple[shift2].rgbtGreen;;
image[shift].rgbRed := lpColorsTriple[shift2].rgbtRed;
image[shift].rgbReserved := 255;
end;
end;
end;
8: // 256色
begin
for y := 0 to height - 1 do
begin
image := D.GetScanline(y);
for x := 0 to width - 1 do
begin
shift := x;
shift2 := (x + (height - y - 1) * width);
index := lpXor[shift2];
image[shift].rgbBlue := lpColors[index].rgbBlue;
image[shift].rgbGreen := lpColors[index].rgbGreen;
image[shift].rgbRed := lpColors[index].rgbRed;
image[shift].rgbReserved := 255;
end;
end;
end;
4: // 16色
begin
for y := 0 to height - 1 do
begin
image := D.GetScanline(y);
for x := 0 to width - 1 do
begin
shift := x;
shift2 := (x + (height - y - 1) * width);
Index := lpXor[shift2 div 2];
if (shift2 mod 2) = 0 then
Index := (Index shr 4) and $F
else
Index := Index and $F;
image[shift].rgbBlue := lpColors[Index].rgbBlue;
image[shift].rgbGreen := lpColors[Index].rgbGreen;
image[shift].rgbRed := lpColors[Index].rgbRed;
image[shift].rgbReserved := 255;
end;
end;
end;
1: // 两色
begin
boundary := width;
while (boundary mod 32) <> 0 do
Inc(boundary); // 32bit对齐
//
for y := 0 to height - 1 do
begin
image := D.GetScanline(y);
for x := 0 to width - 1 do
begin
shift := x;
shift2 := (x + (height - y - 1) * boundary);
index := lpXor[shift2 div 8];
bit := 7 - (x mod 8);
index := (index shr bit) and $01;
image[shift].rgbBlue := lpColors[index].rgbBlue;
image[shift].rgbGreen := lpColors[index].rgbGreen;;
image[shift].rgbRed := lpColors[index].rgbRed;
image[shift].rgbReserved := 255;
end;
end;
end;
end;
// if False then
if hasAndMask then
begin
// 定位AndMask的位置
boundary := width * realBitsCount; // 换算到位
while (boundary mod 32) <> 0 do
Inc(boundary);
lpAnd := lpXor + (boundary * height div 8); // div 8 换算到字节
// 计算对齐的宽度
boundary := width;
while (boundary mod 32) <> 0 do
Inc(boundary); // 32bit对齐
for y := 0 to height - 1 do
begin
image := D.GetScanline(y);
for x := 0 to width - 1 do
begin
shift := x;
bit := 7 - (x mod 8);
shift2 := (x + (height - y - 1) * boundary) div 8;
mask := ($01 and (lpAnd[shift2] shr bit));
image[shift].rgbReserved := image[shift].rgbReserved * (1 - mask);
end;
end;
end;
Abmp.Unmap(D);
end;
end;
function LoadIconByBuf(ABuf: PBYTE; ACount: Integer; Abmps: TBmpList): Boolean;
var
ICONDIR: PIconDir ABSOLUTE ABuf;
iconDirEntry: PIconDirEntry;
IconImage: PICONIMAGE;
i: Integer;
isPngFormat: Boolean;
lBmp: Tbitmap;
begin
Result := False;
if (ICONDIR^.idReserved <> 0) or (ICONDIR^.idType <> 1) or
(ICONDIR^.idCount <= 0) then
Exit;
for i := 0 to ICONDIR^.idCount - 1 do
begin
iconDirEntry := @ICONDIR^.idEntries[i];
IconImage := PICONIMAGE(@ABuf[iconDirEntry.dwImageOffset]);
// 新格式的ICON里面可以包含PNG图片
isPngFormat := PNG_Signature = PUint64(IconImage)^;
lBmp := Tbitmap.Create;
if isPngFormat then
begin
LoadPngFrame(PBYTE(IconImage), iconDirEntry^.dwBytesInRes, lBmp);
end
else
begin
LoadIconFrame(ICONDIR, iconDirEntry, IconImage, lBmp);
end;
Abmps.Add(lBmp);
Result := True;
end;
end;
{$POINTERMATH OFF}
end.
你好,有个问题想请教下,冒昧写在这里了。
我的程序是EXE+DLL结构,在DLL里面我写了一些基本的异常处理代码。
其他的异常我想在ApplicationEvents.OnException事件里面处理,
但是我在这个事件里面,怎么才能知道,是哪个DLL文件引发的异常呢?
我查了一下,System.ExceptAddr这个变量是引发异常的地址,根据这个我是否可以知道是哪个DLL文件,甚至是哪个函数吗?
如蒙回复邮件,不胜感激!!谢谢。
Pingback引用通告: 43ytr.icu/j/GPoAr
Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí Ëîñòôèëüì
Pingback引用通告: Èãðà ïðåñòîëîâ 8 ñåçîí
Pingback引用通告: abisko.ru
Pingback引用通告: glyxar.ru
Pingback引用通告: 2021
Pingback引用通告: ðîêåòìåí
Pingback引用通告: wwin-tv.com
Pingback引用通告: Video
Pingback引用通告: Watch
Pingback引用通告: watch videos
Pingback引用通告: watch online
Pingback引用通告: 00-tv.com
Pingback引用通告: 4serial.com
Pingback引用通告: kino
Pingback引用通告: hs;br
Pingback引用通告: tureckie_serialy_na_russkom_jazyke
Pingback引用通告: tureckie_serialy
Pingback引用通告: serialy
Pingback引用通告: +1+
Pingback引用通告: æóêè+2+ñåðèÿ
Pingback引用通告: Ñìîòðåòü ñåðèàëû îíëàéí âñå ñåðèè ïîäðÿä
Pingback引用通告: Ñìîòðåòü âñå ñåðèè ïîäðÿä
Pingback引用通告: âûòîïêà âîñêà
Pingback引用通告: ++++++
Pingback引用通告: HD-720
Pingback引用通告: guardians+of+the+galaxy+2
Pingback引用通告: strong woman do bong soon
Pingback引用通告: my id is gangnam beauty
Pingback引用通告: guardians of the galaxy vol 2
Pingback引用通告: 2020
Pingback引用通告: kpop+star+season+6+ep+9
Pingback引用通告: 1 2 3 4 5 6 7 8 9 10
Pingback引用通告: Watch TV Shows
Pingback引用通告: Kinokrad 2019 Kinokrad Hd
Pingback引用通告: Kinokrad
Pingback引用通告: filmy-kinokrad
Pingback引用通告: kinokrad-2019
Pingback引用通告: filmy-2019-kinokrad
Pingback引用通告: serial
Pingback引用通告: cerialest.ru
Pingback引用通告: youtube2019.ru
Pingback引用通告: dorama hdrezka
Pingback引用通告: movies hdrezka
Pingback引用通告: HDrezka
Pingback引用通告: kinosmotretonline
Pingback引用通告: LostFilm HD 720
Pingback引用通告: trustedmdstorefy.com
Pingback引用通告: bofilm ñåðèàë
Pingback引用通告: bofilm
Pingback引用通告: 1 seriya
Pingback引用通告: Êîíñóëüòàöèÿ ïñèõîëîãà
Pingback引用通告: topedstoreusa.com
Pingback引用通告: hqcialismht.com
Pingback引用通告: viagramdtrustser.com
Pingback引用通告: rick and morty season 3
Pingback引用通告: See-Season-1
Pingback引用通告: Evil-Season-1
Pingback引用通告: Evil-Season-2
Pingback引用通告: Evil-Season-3
Pingback引用通告: Evil-Season-4
Pingback引用通告: Dollface-Season-1
Pingback引用通告: Queer-Eye-We-re-in-Japan-Season-1
Pingback引用通告: serial 2020
Pingback引用通告: Dailymotion
Pingback引用通告: Watch+movies+2020
Pingback引用通告: serial-video-film-online
Pingback引用通告: tvrv.ru
Pingback引用通告: 1plus1serial.site
Pingback引用通告: #1plus1
Pingback引用通告: 1plus1
Pingback引用通告: Watch Movies Online
Pingback引用通告: Film
Pingback引用通告: Film 2020
Pingback引用通告: Film 2021
Pingback引用通告: Top 10 Best
Pingback引用通告: watch online TV LIVE
Pingback引用通告: parazity-oskar-2020
Pingback引用通告: human design
Pingback引用通告: DSmlka
Pingback引用通告: viagra
Pingback引用通告: generic viagra
Pingback引用通告: +
Pingback引用通告: ¯jak Son³k
Pingback引用通告: astrolog
Pingback引用通告: film-kalashnikov-watch
Pingback引用通告: generic cialis
Pingback引用通告: cialis 20mg
Pingback引用通告: kinoxaxru.ru
Pingback引用通告: pobachennya u vegas
Pingback引用通告: Proshanie so Stalinym
Pingback引用通告: strelcov 2020
Pingback引用通告: film t-34
Pingback引用通告: online pharmacy
Pingback引用通告: canadian pharmacy
Pingback引用通告: Beograd film 2020
Pingback引用通告: psiholog
Pingback引用通告: psixolog
Pingback引用通告: psyhelp_on_line
Pingback引用通告: coronavirus
Pingback引用通告: PSYCHOSOCIAL
Pingback引用通告: rasstanovka hellinger
Pingback引用通告: Cherekasi film 2020
Pingback引用通告: film doktor_liza
Pingback引用通告: djoker film
Pingback引用通告: t.me/psyhell
Pingback引用通告: Ïñèõîëîã îíëàéí
Pingback引用通告: bitly.com
Pingback引用通告: viagra 100mg
Pingback引用通告: viagra price
Pingback引用通告: viagra generic
Pingback引用通告: viagra coupon
Pingback引用通告: cheap viagra
Pingback引用通告: cialis
Pingback引用通告: cialis coupon
Pingback引用通告: canadian pharmacy cialis
Pingback引用通告: cialis 5mg
Pingback引用通告: rlowcostmd.com
Pingback引用通告: bitly
Pingback引用通告: movies-tekstmovies-tekst
Pingback引用通告: Zemlyane 2005 smotret onlajn
Pingback引用通告: smotret onlajn besplatno v kachestve hd 1080
Pingback引用通告: gusmeasu.com
Pingback引用通告: movies-unhinged-film
Pingback引用通告: malenkie-zhenshhiny-2020
Pingback引用通告: dom 2
Pingback引用通告: zoom-psykholog
Pingback引用通告: zoom-viber-skype
Pingback引用通告: Vratar Galaktiki Film, 2020
Pingback引用通告: Vratar
Pingback引用通告: Cherkassy 2020
Pingback引用通告: chernobyl-hbo-2019-1-sezon
Pingback引用通告: moskva-psiholog
Pingback引用通告: batmanapollo.ru
Pingback引用通告: 323
Pingback引用通告: 525
Pingback引用通告: dom2-ru
Pingback引用通告: Tenet Online
Pingback引用通告: psy psy psy psy
Pingback引用通告: krsmi.ru
Pingback引用通告: like-v.ru
Pingback引用通告: CFOSPUK
Pingback引用通告: MAMprEj
Pingback引用通告: fgu0ygW
Pingback引用通告: batmanapollo
Pingback引用通告: tsoy
Pingback引用通告: 44548
Pingback引用通告: 44549
Pingback引用通告: hod-korolevy-2020
Pingback引用通告: HD
Pingback引用通告: 158444
Pingback引用通告: groznyy-serial-2020
Pingback引用通告: 38QvPmk
Pingback引用通告: bitly.com/doctor-strange-hd
Pingback引用通告: bitly.com/eternals-online
Pingback引用通告: bitly.com/maior-grom
Pingback引用通告: matrica-film
Pingback引用通告: dzhonuikfilm4
Pingback引用通告: bitly.com/batman20212022
Pingback引用通告: bitly.com/venom-2-smotret-onlajn
Pingback引用通告: bitly.com/nevremyaumirat
Pingback引用通告: bitly.com/kingsmankingsman
Pingback引用通告: bitly.com/3zaklyatie3
Pingback引用通告: bitly.com/1dreykfilm
Pingback引用通告: bitly.com/topgunmavericktopgun
Pingback引用通告: bitly.com/flash2022
Pingback引用通告: bitly.com/fantasticheskietvari3
Pingback引用通告: bitly.com/wonderwoman1984hd
Pingback引用通告: 1444
Pingback引用通告: cleantalkorg2.ru
Pingback引用通告: 232dfsad
Pingback引用通告: cleantalkorg2.ru/sitemap.xml
Pingback引用通告: join vk
Pingback引用通告: vk login
Pingback引用通告: svaty7sezon
Pingback引用通告: svaty 7 sezon
Pingback引用通告: svaty 7
Pingback引用通告: tik tok
Pingback引用通告: 666
Pingback引用通告: The Revenant
Pingback引用通告: 2021
Pingback引用通告: D4
Pingback引用通告: 777
Pingback引用通告: link
Pingback引用通告: 4569987
Pingback引用通告: news news news
Pingback引用通告: psy
Pingback引用通告: psy2022
Pingback引用通告: projectio-freid
Pingback引用通告: kinoteatrzarya.ru
Pingback引用通告: topvideos
Pingback引用通告: afisha-kinoteatrov.ru
Pingback引用通告: Ukrainskie-serialy
Pingback引用通告: site
Pingback引用通告: top
Pingback引用通告: soderzhanki-3-sezon-2021.online