koishi-plugin-memesluna 0.4.2 → 0.4.4
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/lib/index.js +34 -42
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -64,15 +64,6 @@ function hashImageBuffer(buffer) {
|
|
|
64
64
|
return (0, import_crypto.createHash)("sha256").update(buffer).digest("hex");
|
|
65
65
|
}
|
|
66
66
|
__name(hashImageBuffer, "hashImageBuffer");
|
|
67
|
-
function loadJimp() {
|
|
68
|
-
try {
|
|
69
|
-
const jimpModule = require("jimp");
|
|
70
|
-
return jimpModule.Jimp || jimpModule.default?.Jimp || null;
|
|
71
|
-
} catch {
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
__name(loadJimp, "loadJimp");
|
|
76
67
|
function loadOptionalSharp() {
|
|
77
68
|
try {
|
|
78
69
|
const packageName = "sharp";
|
|
@@ -83,6 +74,15 @@ function loadOptionalSharp() {
|
|
|
83
74
|
}
|
|
84
75
|
}
|
|
85
76
|
__name(loadOptionalSharp, "loadOptionalSharp");
|
|
77
|
+
function loadPhoton() {
|
|
78
|
+
try {
|
|
79
|
+
const packageName = "@cf-wasm/photon/node";
|
|
80
|
+
return require(packageName);
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
__name(loadPhoton, "loadPhoton");
|
|
86
86
|
function countHexBitDistance(a, b) {
|
|
87
87
|
if (!a || !b || a.length !== b.length) return 64;
|
|
88
88
|
let distance = 0;
|
|
@@ -104,28 +104,15 @@ function lumaFromRgba(data, offset) {
|
|
|
104
104
|
return 0.299 * r + 0.587 * g + 0.114 * b;
|
|
105
105
|
}
|
|
106
106
|
__name(lumaFromRgba, "lumaFromRgba");
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
const xEnd = Math.max(xStart + 1, Math.floor((cellX + 1) * width / DHASH_WIDTH));
|
|
110
|
-
const yStart = Math.floor(cellY * height / DHASH_HEIGHT);
|
|
111
|
-
const yEnd = Math.max(yStart + 1, Math.floor((cellY + 1) * height / DHASH_HEIGHT));
|
|
112
|
-
let total = 0;
|
|
113
|
-
let count = 0;
|
|
114
|
-
for (let y = yStart; y < Math.min(yEnd, height); y++) {
|
|
115
|
-
for (let x = xStart; x < Math.min(xEnd, width); x++) {
|
|
116
|
-
total += lumaFromRgba(data, (y * width + x) * 4);
|
|
117
|
-
count++;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return count ? total / count : 0;
|
|
121
|
-
}
|
|
122
|
-
__name(averageCellLuma, "averageCellLuma");
|
|
123
|
-
function buildDhashFromLumaGrid(samples) {
|
|
107
|
+
function buildDhashFromRgbaPixels(raw) {
|
|
108
|
+
if (raw.length < DHASH_WIDTH * DHASH_HEIGHT * 4) return "";
|
|
124
109
|
let bits = "";
|
|
125
110
|
for (let y = 0; y < DHASH_HEIGHT; y++) {
|
|
126
|
-
const row = y * DHASH_WIDTH;
|
|
111
|
+
const row = y * DHASH_WIDTH * 4;
|
|
127
112
|
for (let x = 0; x < DHASH_WIDTH - 1; x++) {
|
|
128
|
-
|
|
113
|
+
const left = lumaFromRgba(raw, row + x * 4);
|
|
114
|
+
const right = lumaFromRgba(raw, row + (x + 1) * 4);
|
|
115
|
+
bits += left > right ? "1" : "0";
|
|
129
116
|
}
|
|
130
117
|
}
|
|
131
118
|
let hex = "";
|
|
@@ -134,7 +121,7 @@ function buildDhashFromLumaGrid(samples) {
|
|
|
134
121
|
}
|
|
135
122
|
return hex;
|
|
136
123
|
}
|
|
137
|
-
__name(
|
|
124
|
+
__name(buildDhashFromRgbaPixels, "buildDhashFromRgbaPixels");
|
|
138
125
|
var RESERVED_PATHS = /* @__PURE__ */ new Set([
|
|
139
126
|
"config",
|
|
140
127
|
"admin",
|
|
@@ -357,21 +344,26 @@ var MemesLunaService = class extends import_koishi.Service {
|
|
|
357
344
|
await this.backfillImageFingerprints();
|
|
358
345
|
}
|
|
359
346
|
async getImagePerceptualHash(buffer) {
|
|
360
|
-
const
|
|
361
|
-
if (
|
|
347
|
+
const photon = loadPhoton();
|
|
348
|
+
if (photon) {
|
|
349
|
+
let inputImage = null;
|
|
350
|
+
let resizedImage = null;
|
|
362
351
|
try {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
for (let y = 0; y < DHASH_HEIGHT; y++) {
|
|
368
|
-
for (let x = 0; x < DHASH_WIDTH; x++) {
|
|
369
|
-
samples.push(averageCellLuma(data, width, height, x, y));
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
return buildDhashFromLumaGrid(samples);
|
|
352
|
+
inputImage = photon.PhotonImage.new_from_byteslice(new Uint8Array(buffer));
|
|
353
|
+
resizedImage = photon.resize(inputImage, DHASH_WIDTH, DHASH_HEIGHT, photon.SamplingFilter.Nearest);
|
|
354
|
+
const hash = buildDhashFromRgbaPixels(resizedImage.get_raw_pixels());
|
|
355
|
+
if (hash) return hash;
|
|
373
356
|
} catch (error) {
|
|
374
|
-
this.ctx.logger("memesluna").debug(`
|
|
357
|
+
this.ctx.logger("memesluna").debug(`Failed to calculate perceptual hash with photon: ${error.message}`);
|
|
358
|
+
} finally {
|
|
359
|
+
try {
|
|
360
|
+
resizedImage?.free?.();
|
|
361
|
+
} catch {
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
inputImage?.free?.();
|
|
365
|
+
} catch {
|
|
366
|
+
}
|
|
375
367
|
}
|
|
376
368
|
}
|
|
377
369
|
const sharp = loadOptionalSharp();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-memesluna",
|
|
3
3
|
"description": "Image Forward service for Koishi with ChatLuna integration",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.4",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"node": ">=18.0.0"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"
|
|
44
|
+
"@cf-wasm/photon": "^0.3.6",
|
|
45
45
|
"koishi-plugin-chatluna": "^1.3.0-alpha.49",
|
|
46
46
|
"koishi-plugin-chatluna-storage-service": "^1.0.6"
|
|
47
47
|
},
|