昨天在使用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