这是我正在使用的代码。(代码在这篇文章的底部,但这里是GitHubGist :: Noitidart / _ff-addon-snippet-browseForBadgeThenCreateSaveAnApply.js 的链接)它是复制粘贴到暂存器(我试过小提琴,但它需要特权范围)。当您运行时,它会要求您选择 16x16 图像。然后它将获取Firefox图标并将其放在画布上,然后获取您浏览到的图标并将其覆盖在右下角。然后它会将其转换为和.ico
保存到您的桌面。然后它将更改所有 Firefox 窗口的图标。profilist16.ico
profilist32.ico
完成上述操作后,请打开一个新的 firefox 窗口,然后在 alt+tab 中您会看到带有徽章图标的 firefox 徽标更脏。
在底部,您会看到原始画布绘图(它看起来很模糊,但我认为那是我在 Firefox 上的缩放级别)。图标很清晰,但是如果您注意到边缘(尤其是顶部)上的带徽章的图标(右侧),您会看到污垢,例如在通常图标(左侧)中看不到的黑色锯齿状的东西
var win = Services.wm.getMostRecentWindow(null);
var me = win;
//these should be global vars
var sizes = []; //os dependent
var img = {}; //holds Image for each size image
var osIconFileType = 'ico'; //os dependent
var cOS = 'Windows';
function badgeIt() {
var fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(win, "Select Badge Image", Ci.nsIFilePicker.modeOpen);
var fpCallback = function(rv) {
if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
if (sizes.length == 0) {
//figure out what os this is and populate sizes withthe sizes needed for this os
sizes = [32, 16]; //note: ask on SO how to determine what sizes the os uses for its icons?
}
loadBadgeImage();
} else {
//user did not select an file to badge with
}
}
var ranOnce0 = false;
var checkAllDefaultImagesLoaded = function() {
for (var i=0; i<sizes.length; i++) {
//console.log('img.sizes[i].loaded for i = ' + sizes[i] + ' is == ' + uneval(img[sizes[i]]));
if (!img[sizes[i]] || !img[sizes[i]].loaded) {
console.log('returning false as sizes[i]', sizes[i], 'is not loaded yet')
return false; //return as not yet all are done
}
//me.alert('all img sizes loaded');
}
//ok all sizes loaded
if (ranOnce0) {
alert('already ranOnce0 so return false');
return false;
}
ranOnce0 = true;
return true;
}
var loadDefaultImages = function() {
for (var i=0; i<sizes.length; i++) {
img[sizes[i]] = {};
img[sizes[i]].Image = new Image();
img[sizes[i]].Image.onload = function(iBinded) {
console.log('i', iBinded);
//console.log('img', img);
console.log('sizes[i]', sizes[iBinded]);
console.log('img[sizes[iBinded]].loaded=', uneval(img[sizes[iBinded]]), 'will now set it to true')
img[sizes[iBinded]].loaded = true;
console.log('just loaded size of (sizes[iBinded]) = ' + sizes[iBinded]);
var allLoaded = checkAllDefaultImagesLoaded();
if (allLoaded == true) {
console.log('allLoaded == true so createAndSave')
createAndSaveIcons();
} else {
console.warn('allLoaded is false so dont create')
}
}.bind(null, i)
img[sizes[i]].Image.src = 'chrome://branding/content/icon' + sizes[i] + '.png';
}
}
var loadBadgeImage = function() {
console.log('loadBadgeImage')
img.badge = {};
img.badge.Image = new Image();
img.badge.Image.onload = function() {
console.log('bagde image loaded')
img.badge.loaded = true;
if (checkAllDefaultImagesLoaded()) {
console.log('all dfault images PRELOADED so continue to createAndSaveIcons')
createAndSaveIcons();
} else {
console.log('all default images not loaded so start loading them')
loadDefaultImages();
}
}
img.badge.Image.src = Services.io.newFileURI(fp.file).spec;
}
var badgedIconMade = {};
var ranOnce = false;
var checkAllBadgedIconsMade = function() {
for (var i=0; i<sizes.length; i++) {
if (!badgedIconMade[sizes[i]]) {
return; //not yt done making
}
}
if (ranOnce) {
alert('already ranOnce so return');
return;
}
ranOnce = true;
// all badged icons made
applyIcons();
}
var blobCallback = function(size) {
return function (b) {
var r = new FileReader();
r.onloadend = function () {
// r.result contains the ArrayBuffer.
//alert(r.result)
img[size].ArrayBuffer = r.result;
badgedIconMade[size] = true;
//checkAllBadgedIconsMade();
Cu.import('resource://gre/modules/osfile.jsm');
var writePath = OS.Path.join(OS.Constants.Path.desktopDir, 'profilist' + size + '.' + osIconFileType);
console.log('writePath', writePath)
var promise = OS.File.writeAtomic(writePath, new Uint8Array(r.result), {tmpPath:writePath + '.tmp'});
promise.then(
function() {
//win.alert('success')
checkAllBadgedIconsMade();
},
function() {
//win.alert('failure')
}
);
};
//var url = window.URL.createObjectURL(b)
//img[size].blobUrl = url;
//prompt('', url)
r.readAsArrayBuffer(b);
}
}
var createAndSaveIcons = function() {
console.log('createAndSave')
var canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
var ctx = canvas.getContext('2d');
gBrowser.contentDocument.documentElement.appendChild(canvas);
var badgeDim = { //holds key which is size of default icon, and the value is the dimension to draw the badge for that default icon size //this is set by me the dev, maybe make preference for this for user
'16': 10,
'32': 16
};
for (var i=0; i<sizes.length; i++) {
canvas.width = sizes[i];
canvas.height = sizes[i];
ctx.clearRect(0, 0, sizes[i], sizes[i]);
ctx.drawImage(img[sizes[i]].Image, 0, 0);
if (sizes[i] in badgeDim) {
if (badgeDim[sizes[i]] != sizes[i]) { //before i had `img.badge.Image.width` in place of `sizes[i]`, but can just use sizes[i] because thats the dim of the default icon duh
ctx.drawImage(img.badge.Image, sizes[i]-badgeDim[sizes[i]], sizes[i]-badgeDim[sizes[i]], badgeDim[sizes[i]], badgeDim[sizes[i]]);
} else {
//the redim size is same as icon size anyways so just draw it
ctx.drawImage(img.badge.Image, sizes[i]-badgeDim[sizes[i]], sizes[i]-badgeDim[sizes[i]]);
}
} else {
//sizes[i] is not in badgeDim meaning i dont care what size the badge is on this size of icon
ctx.drawImage(img.badge.Image, sizes[i]-badgeDim[sizes[i]], sizes[i]-badgeDim[sizes[i]]);
}
//canvas.mozFetchAsStream(mfasCallback(sizes[i]), 'image/vnd.microsoft.icon')
canvas.toBlob(blobCallback(sizes[i]), "image/vnd.microsoft.icon", "-moz-parse-options:format=bmp;bpp=32");
}
}
var applyIcons = function() {
if (cOS == 'Windows') {
Cu.import('resource://gre/modules/ctypes.jsm');
var user32 = ctypes.open('user32.dll');
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms644950%28v=vs.85%29.aspx
* LRESULT WINAPI SendMessage(
* __in HWND hWnd,
* __in UINT Msg,
* __in WPARAM wParam,
* __in LPARAM lParam
* );
*/
var SendMessage = user32.declare('SendMessageW', ctypes.winapi_abi, ctypes.uintptr_t,
ctypes.voidptr_t,
ctypes.unsigned_int,
ctypes.int32_t,
ctypes.voidptr_t
);
/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045%28v=vs.85%29.aspx
* HANDLE WINAPI LoadImage(
* __in_opt_ HINSTANCE hinst,
* __in_ LPCTSTR lpszName,
* __in_ UINT uType,
* __in_ int cxDesired,
* __in_ int cyDesired,
* __in_ UINT fuLoad
* );
*/
var LoadImage = user32.declare('LoadImageA', ctypes.winapi_abi, ctypes.voidptr_t,
ctypes.voidptr_t,
ctypes.char.ptr,
ctypes.unsigned_int,
ctypes.int,
ctypes.int,
ctypes.unsigned_int
);
var IMAGE_BITMAP = 0;
var IMAGE_ICON = 1;
var LR_LOADFROMFILE = 16;
var DOMWindows = Services.wm.getEnumerator(null);
while (DOMWindows.hasMoreElements()) {
var aDOMWindow = DOMWindows.getNext();
var baseWindow = aDOMWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.nsIBaseWindow;
var nativeHandle = baseWindow.nativeHandle;
var targetWindow_handle = ctypes.voidptr_t(ctypes.UInt64(nativeHandle));
console.log('aappplying now')
var hIconBig = LoadImage(targetWindow_handle, OS.Path.join(OS.Constants.Path.desktopDir, 'profilist32.' + osIconFileType), IMAGE_ICON, 32, 32, LR_LOADFROMFILE); //MUST BE A FILEPATH TO A ICO!!!
var hIconSmall = LoadImage(targetWindow_handle, OS.Path.join(OS.Constants.Path.desktopDir, 'profilist16.' + osIconFileType), IMAGE_ICON, 16, 16, LR_LOADFROMFILE); //MUST BE A FILEPATH TO A ICO!!!
var successSmall = SendMessage(targetWindow_handle, 0x0080 /** WM_SETICON **/ , 0 /** ICON_SMALL **/ , hIconSmall); //if it was success it will return 0? im not sure. on first time running it, and it was succesful it returns 0 for some reason
var successBig = SendMessage(targetWindow_handle, 0x0080 /** WM_SETICON **/ , 1 /** ICON_BIG **/ , hIconBig); //if it was success it will return 0? im not sure. on first time running it, and it was succesful it returns 0 for some reason
}
user32.close();
}
}
fp.open(fpCallback);
}
badgeIt();