@aiyiran/myclaw 1.0.85 → 1.0.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/openclaw.ico +0 -0
- package/lobster-icon-generator.html +108 -36
- package/package.json +1 -1
package/assets/openclaw.ico
CHANGED
|
Binary file
|
|
@@ -91,10 +91,12 @@
|
|
|
91
91
|
<!-- 画布分辨率提升,渲染战斗姿态和旋转 -->
|
|
92
92
|
<canvas id="iconCanvas" width="256" height="256"></canvas>
|
|
93
93
|
<br>
|
|
94
|
-
<
|
|
94
|
+
<div style="display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;">
|
|
95
|
+
<button onclick="downloadIcon()">⬇️ 下载为 PNG 格式</button>
|
|
96
|
+
<button onclick="downloadICO()" style="background: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%); box-shadow: 0 0 15px rgba(6, 182, 212, 0.4);">⬇️ 下载为 ICO 格式</button>
|
|
97
|
+
</div>
|
|
95
98
|
<div class="desc">
|
|
96
|
-
|
|
97
|
-
你可以用第三方工具把下载的 PNG 转换为 .ico 文件。
|
|
99
|
+
PNG 为原始图片,ICO 包含 16/32/48/256 四种尺寸,可直接用于桌面图标。
|
|
98
100
|
</div>
|
|
99
101
|
</div>
|
|
100
102
|
</div>
|
|
@@ -150,40 +152,40 @@
|
|
|
150
152
|
"0CC00000000CC0"
|
|
151
153
|
];
|
|
152
154
|
|
|
153
|
-
//
|
|
155
|
+
// 我们运用巧妙的数组映射排布:钳子聚集在矩阵顶部(对应视觉左下角),而矩阵的中下大段空位全部绘制极致华丽且粗壮的机甲身躯与尾摆(对应视觉右上角)!
|
|
154
156
|
const design32 = [
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
167
|
-
"
|
|
168
|
-
"
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
"
|
|
157
|
+
"0000000000000R0000R0000000000000",
|
|
158
|
+
"000000000000RRC00CRR000000000000",
|
|
159
|
+
"00000000000RRRC00CRRR00000000000",
|
|
160
|
+
"0000000000RRBR0000RBRR0000000000",
|
|
161
|
+
"000000000RRBBR0000RBBRR000000000",
|
|
162
|
+
"00000000RRBBBRC00CRBBBRR00000000",
|
|
163
|
+
"0000000RRBBBBRC00CRBBBBRR0000000",
|
|
164
|
+
"000000RRRBBBBRC00CRBBBBRRR000000",
|
|
165
|
+
"00000RRRRBBBBRC00CRBBBBRRRR00000",
|
|
166
|
+
"000000RRRBBBBRC00CRBBBBRRR000000",
|
|
167
|
+
"0000000RRBBBBRC00CRBBBBRR0000000",
|
|
168
|
+
"00000000RRBBBR0000RBBBRR00000000",
|
|
169
|
+
"000000000RRBBR0000RBBRR000000000",
|
|
170
|
+
"0000000000RRBR0000RBRR0000000000",
|
|
171
|
+
"00000000000RRR0000RRR00000000000",
|
|
172
|
+
"000000000000RR0000RR000000000000",
|
|
173
|
+
"0000000000RR0WDDDDW0RR0000000000",
|
|
174
|
+
"00000000000RBC0CC0CBR00000000000",
|
|
175
|
+
"00000000000CBBBCCBBBC00000000000",
|
|
176
|
+
"0000000000CBBBBCCBBBBC0000000000",
|
|
177
|
+
"0000000000CBBBCCCCBBBC0000000000",
|
|
178
|
+
"000000000CBBBBC00CBBBBC000000000",
|
|
179
|
+
"000000000CBBBBC00CBBBBC000000000",
|
|
180
|
+
"000000000CCBBBC00CBBBCC000000000",
|
|
181
|
+
"00000000CBBBBBC00CBBBBBC00000000",
|
|
182
|
+
"0000000CBBBBBBC00CBBBBBBC0000000",
|
|
183
|
+
"000000CBBBCBBBC00CBBBCBBBC000000",
|
|
184
|
+
"00000CBBBC0CBBC00CBBC0CBBBC00000",
|
|
185
|
+
"00000CBBBC00CB0000BC00CBBBC00000",
|
|
186
|
+
"0000CBBBC0000C0000C0000CBBBC0000",
|
|
187
|
+
"000CBBBC0000000000000000CBBBC000",
|
|
188
|
+
"00CCCCC00000000000000000CCCCC00"
|
|
187
189
|
];
|
|
188
190
|
|
|
189
191
|
const canvas = document.getElementById('iconCanvas');
|
|
@@ -228,6 +230,76 @@
|
|
|
228
230
|
link.href = dataURL;
|
|
229
231
|
link.click();
|
|
230
232
|
}
|
|
233
|
+
|
|
234
|
+
// ====== ICO 生成逻辑 ======
|
|
235
|
+
// 将 Canvas 缩放到指定尺寸并返回 PNG 的 Uint8Array
|
|
236
|
+
function canvasToPngBytes(srcCanvas, targetSize) {
|
|
237
|
+
const tmp = document.createElement('canvas');
|
|
238
|
+
tmp.width = targetSize;
|
|
239
|
+
tmp.height = targetSize;
|
|
240
|
+
const tctx = tmp.getContext('2d');
|
|
241
|
+
// 对小尺寸禁用平滑,保持像素锐利
|
|
242
|
+
tctx.imageSmoothingEnabled = (targetSize > 48);
|
|
243
|
+
tctx.drawImage(srcCanvas, 0, 0, targetSize, targetSize);
|
|
244
|
+
const dataURL = tmp.toDataURL('image/png');
|
|
245
|
+
const base64 = dataURL.split(',')[1];
|
|
246
|
+
const binary = atob(base64);
|
|
247
|
+
const bytes = new Uint8Array(binary.length);
|
|
248
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
249
|
+
return bytes;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function buildICO(pngArrays, sizes) {
|
|
253
|
+
// ICO 文件结构:
|
|
254
|
+
// ICONDIR (6 bytes) + N x ICONDIRENTRY (16 bytes each) + N x PNG data
|
|
255
|
+
const numImages = pngArrays.length;
|
|
256
|
+
const headerSize = 6 + numImages * 16;
|
|
257
|
+
let totalSize = headerSize;
|
|
258
|
+
for (const png of pngArrays) totalSize += png.length;
|
|
259
|
+
|
|
260
|
+
const buffer = new ArrayBuffer(totalSize);
|
|
261
|
+
const view = new DataView(buffer);
|
|
262
|
+
|
|
263
|
+
// ICONDIR header
|
|
264
|
+
view.setUint16(0, 0, true); // reserved
|
|
265
|
+
view.setUint16(2, 1, true); // type: 1 = ICO
|
|
266
|
+
view.setUint16(4, numImages, true); // image count
|
|
267
|
+
|
|
268
|
+
let dataOffset = headerSize;
|
|
269
|
+
for (let i = 0; i < numImages; i++) {
|
|
270
|
+
const entryOffset = 6 + i * 16;
|
|
271
|
+
const s = sizes[i];
|
|
272
|
+
const pngData = pngArrays[i];
|
|
273
|
+
|
|
274
|
+
view.setUint8(entryOffset + 0, s >= 256 ? 0 : s); // width (0 = 256)
|
|
275
|
+
view.setUint8(entryOffset + 1, s >= 256 ? 0 : s); // height
|
|
276
|
+
view.setUint8(entryOffset + 2, 0); // color palette count
|
|
277
|
+
view.setUint8(entryOffset + 3, 0); // reserved
|
|
278
|
+
view.setUint16(entryOffset + 4, 1, true); // color planes
|
|
279
|
+
view.setUint16(entryOffset + 6, 32, true); // bits per pixel
|
|
280
|
+
view.setUint32(entryOffset + 8, pngData.length, true); // data size
|
|
281
|
+
view.setUint32(entryOffset + 12, dataOffset, true); // data offset
|
|
282
|
+
|
|
283
|
+
// 写入 PNG 数据
|
|
284
|
+
const dst = new Uint8Array(buffer, dataOffset, pngData.length);
|
|
285
|
+
dst.set(pngData);
|
|
286
|
+
dataOffset += pngData.length;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return new Blob([buffer], { type: 'image/x-icon' });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function downloadICO() {
|
|
293
|
+
const sizes = [16, 32, 48, 256];
|
|
294
|
+
const pngArrays = sizes.map(s => canvasToPngBytes(canvas, s));
|
|
295
|
+
const blob = buildICO(pngArrays, sizes);
|
|
296
|
+
const url = URL.createObjectURL(blob);
|
|
297
|
+
const link = document.createElement('a');
|
|
298
|
+
link.download = 'openclaw-tech-lobster.ico';
|
|
299
|
+
link.href = url;
|
|
300
|
+
link.click();
|
|
301
|
+
URL.revokeObjectURL(url);
|
|
302
|
+
}
|
|
231
303
|
</script>
|
|
232
304
|
</body>
|
|
233
305
|
</html>
|