koishi-plugin-memesluna 0.4.3 → 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.
Files changed (2) hide show
  1. package/lib/index.js +35 -61
  2. package/package.json +3 -6
package/lib/index.js CHANGED
@@ -74,6 +74,15 @@ function loadOptionalSharp() {
74
74
  }
75
75
  }
76
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");
77
86
  function countHexBitDistance(a, b) {
78
87
  if (!a || !b || a.length !== b.length) return 64;
79
88
  let distance = 0;
@@ -87,40 +96,6 @@ __name(countHexBitDistance, "countHexBitDistance");
87
96
  var DHASH_BITS = 64;
88
97
  var DHASH_WIDTH = 9;
89
98
  var DHASH_HEIGHT = 8;
90
- function decodeImagePixels(buffer) {
91
- try {
92
- if (buffer.length >= 8 && buffer.readUInt32BE(0) === 2303741511 && buffer.readUInt32BE(4) === 218765834) {
93
- const png = require("pngjs").PNG.sync.read(buffer);
94
- return { data: png.data, width: png.width, height: png.height };
95
- }
96
- if (buffer.length >= 3 && buffer[0] === 255 && buffer[1] === 216 && buffer[2] === 255) {
97
- const jpeg = require("jpeg-js").decode(buffer, { useTArray: true });
98
- return { data: jpeg.data, width: jpeg.width, height: jpeg.height };
99
- }
100
- if (buffer.length >= 6 && buffer.toString("ascii", 0, 3) === "GIF") {
101
- const { GifReader } = require("omggif");
102
- const reader = new GifReader(buffer);
103
- const data = Buffer.alloc(reader.width * reader.height * 4);
104
- reader.decodeAndBlitFrameRGBA(0, data);
105
- return { data, width: reader.width, height: reader.height };
106
- }
107
- if (buffer.length >= 2 && buffer[0] === 66 && buffer[1] === 77) {
108
- const bmp = require("bmp-js").decode(buffer);
109
- const data = Buffer.alloc(bmp.width * bmp.height * 4);
110
- for (let i = 0; i < bmp.data.length; i += 4) {
111
- data[i] = bmp.data[i + 3];
112
- data[i + 1] = bmp.data[i + 2];
113
- data[i + 2] = bmp.data[i + 1];
114
- data[i + 3] = bmp.data[i];
115
- }
116
- return { data, width: bmp.width, height: bmp.height };
117
- }
118
- } catch {
119
- return null;
120
- }
121
- return null;
122
- }
123
- __name(decodeImagePixels, "decodeImagePixels");
124
99
  function lumaFromRgba(data, offset) {
125
100
  const alpha = data[offset + 3] / 255;
126
101
  const r = data[offset] * alpha + 255 * (1 - alpha);
@@ -129,28 +104,15 @@ function lumaFromRgba(data, offset) {
129
104
  return 0.299 * r + 0.587 * g + 0.114 * b;
130
105
  }
131
106
  __name(lumaFromRgba, "lumaFromRgba");
132
- function averageCellLuma(data, width, height, cellX, cellY) {
133
- const xStart = Math.floor(cellX * width / DHASH_WIDTH);
134
- const xEnd = Math.max(xStart + 1, Math.floor((cellX + 1) * width / DHASH_WIDTH));
135
- const yStart = Math.floor(cellY * height / DHASH_HEIGHT);
136
- const yEnd = Math.max(yStart + 1, Math.floor((cellY + 1) * height / DHASH_HEIGHT));
137
- let total = 0;
138
- let count = 0;
139
- for (let y = yStart; y < Math.min(yEnd, height); y++) {
140
- for (let x = xStart; x < Math.min(xEnd, width); x++) {
141
- total += lumaFromRgba(data, (y * width + x) * 4);
142
- count++;
143
- }
144
- }
145
- return count ? total / count : 0;
146
- }
147
- __name(averageCellLuma, "averageCellLuma");
148
- function buildDhashFromLumaGrid(samples) {
107
+ function buildDhashFromRgbaPixels(raw) {
108
+ if (raw.length < DHASH_WIDTH * DHASH_HEIGHT * 4) return "";
149
109
  let bits = "";
150
110
  for (let y = 0; y < DHASH_HEIGHT; y++) {
151
- const row = y * DHASH_WIDTH;
111
+ const row = y * DHASH_WIDTH * 4;
152
112
  for (let x = 0; x < DHASH_WIDTH - 1; x++) {
153
- bits += samples[row + x] > samples[row + x + 1] ? "1" : "0";
113
+ const left = lumaFromRgba(raw, row + x * 4);
114
+ const right = lumaFromRgba(raw, row + (x + 1) * 4);
115
+ bits += left > right ? "1" : "0";
154
116
  }
155
117
  }
156
118
  let hex = "";
@@ -159,7 +121,7 @@ function buildDhashFromLumaGrid(samples) {
159
121
  }
160
122
  return hex;
161
123
  }
162
- __name(buildDhashFromLumaGrid, "buildDhashFromLumaGrid");
124
+ __name(buildDhashFromRgbaPixels, "buildDhashFromRgbaPixels");
163
125
  var RESERVED_PATHS = /* @__PURE__ */ new Set([
164
126
  "config",
165
127
  "admin",
@@ -382,15 +344,27 @@ var MemesLunaService = class extends import_koishi.Service {
382
344
  await this.backfillImageFingerprints();
383
345
  }
384
346
  async getImagePerceptualHash(buffer) {
385
- const decoded = decodeImagePixels(buffer);
386
- if (decoded) {
387
- const samples = [];
388
- for (let y = 0; y < DHASH_HEIGHT; y++) {
389
- for (let x = 0; x < DHASH_WIDTH; x++) {
390
- samples.push(averageCellLuma(decoded.data, decoded.width, decoded.height, x, y));
347
+ const photon = loadPhoton();
348
+ if (photon) {
349
+ let inputImage = null;
350
+ let resizedImage = null;
351
+ try {
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;
356
+ } catch (error) {
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 {
391
366
  }
392
367
  }
393
- return buildDhashFromLumaGrid(samples);
394
368
  }
395
369
  const sharp = loadOptionalSharp();
396
370
  if (!sharp) return "";
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.3",
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,12 +41,9 @@
41
41
  "node": ">=18.0.0"
42
42
  },
43
43
  "dependencies": {
44
- "bmp-js": "^0.1.0",
45
- "jpeg-js": "^0.4.4",
44
+ "@cf-wasm/photon": "^0.3.6",
46
45
  "koishi-plugin-chatluna": "^1.3.0-alpha.49",
47
- "koishi-plugin-chatluna-storage-service": "^1.0.6",
48
- "omggif": "^1.0.10",
49
- "pngjs": "^7.0.0"
46
+ "koishi-plugin-chatluna-storage-service": "^1.0.6"
50
47
  },
51
48
  "devDependencies": {
52
49
  "@koishijs/client": "^5.30.11",