obsidian-integration-testing 10.1.0 → 10.2.0
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/dist/lib/cjs/fit-screenshot.cjs +124 -0
- package/dist/lib/cjs/fit-screenshot.d.cts +117 -0
- package/dist/lib/cjs/index.cjs +6 -1
- package/dist/lib/cjs/index.d.cts +2 -0
- package/dist/lib/cjs/library.cjs +1 -1
- package/dist/lib/esm/fit-screenshot.d.mts +117 -0
- package/dist/lib/esm/fit-screenshot.mjs +89 -0
- package/dist/lib/esm/index.d.mts +2 -0
- package/dist/lib/esm/index.mjs +7 -1
- package/dist/lib/esm/library.mjs +1 -1
- package/dist/obsidian-integration-testing-10.2.0.tgz +0 -0
- package/package.json +8 -1
- package/dist/obsidian-integration-testing-10.1.0.tgz +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var fit_screenshot_exports = {};
|
|
30
|
+
__export(fit_screenshot_exports, {
|
|
31
|
+
computeFitToCanvas: () => computeFitToCanvas,
|
|
32
|
+
fitScreenshotToCanvas: () => fitScreenshotToCanvas
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(fit_screenshot_exports);
|
|
35
|
+
const DEFAULT_BLUR_SIGMA = 24;
|
|
36
|
+
const MARGIN_SIDES = 2;
|
|
37
|
+
function computeFitToCanvas(params) {
|
|
38
|
+
const {
|
|
39
|
+
canvasHeightInPixels,
|
|
40
|
+
canvasWidthInPixels,
|
|
41
|
+
sourceHeightInPixels,
|
|
42
|
+
sourceWidthInPixels
|
|
43
|
+
} = params;
|
|
44
|
+
const namedDimensions = [
|
|
45
|
+
["canvasHeightInPixels", canvasHeightInPixels],
|
|
46
|
+
["canvasWidthInPixels", canvasWidthInPixels],
|
|
47
|
+
["sourceHeightInPixels", sourceHeightInPixels],
|
|
48
|
+
["sourceWidthInPixels", sourceWidthInPixels]
|
|
49
|
+
];
|
|
50
|
+
for (const [name, value] of namedDimensions) {
|
|
51
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
52
|
+
throw new Error(`computeFitToCanvas: ${name} must be a positive number, got ${String(value)}.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const scaledHeightInPixels = canvasHeightInPixels;
|
|
56
|
+
const exactScaledWidth = sourceWidthInPixels * (canvasHeightInPixels / sourceHeightInPixels);
|
|
57
|
+
const scaledWidthInPixels = roundToMatchingParity(exactScaledWidth, canvasWidthInPixels);
|
|
58
|
+
if (scaledWidthInPixels > canvasWidthInPixels) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`computeFitToCanvas: the source is wider than the canvas once scaled to its height (${String(scaledWidthInPixels)} > ${String(canvasWidthInPixels)}); this fits by height and cannot letterbox.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
const marginInPixels = (canvasWidthInPixels - scaledWidthInPixels) / MARGIN_SIDES;
|
|
64
|
+
return {
|
|
65
|
+
marginInPixels,
|
|
66
|
+
offsetXInPixels: marginInPixels,
|
|
67
|
+
offsetYInPixels: 0,
|
|
68
|
+
scaledHeightInPixels,
|
|
69
|
+
scaledWidthInPixels
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
async function fitScreenshotToCanvas(bytes, options) {
|
|
73
|
+
const {
|
|
74
|
+
blurSigma = DEFAULT_BLUR_SIGMA,
|
|
75
|
+
canvasHeightInPixels,
|
|
76
|
+
canvasWidthInPixels
|
|
77
|
+
} = options;
|
|
78
|
+
const sharp = await importSharp();
|
|
79
|
+
const metadata = await sharp(bytes).metadata();
|
|
80
|
+
const sourceWidthInPixels = metadata.width;
|
|
81
|
+
const sourceHeightInPixels = metadata.height;
|
|
82
|
+
if (sourceWidthInPixels === void 0 || sourceHeightInPixels === void 0) {
|
|
83
|
+
throw new Error("fitScreenshotToCanvas: could not read the source image dimensions.");
|
|
84
|
+
}
|
|
85
|
+
const geometry = computeFitToCanvas({
|
|
86
|
+
canvasHeightInPixels,
|
|
87
|
+
canvasWidthInPixels,
|
|
88
|
+
sourceHeightInPixels,
|
|
89
|
+
sourceWidthInPixels
|
|
90
|
+
});
|
|
91
|
+
const background = await sharp(bytes).resize(canvasWidthInPixels, canvasHeightInPixels, { fit: "cover" }).blur(blurSigma).toBuffer();
|
|
92
|
+
const foreground = await sharp(bytes).resize(geometry.scaledWidthInPixels, geometry.scaledHeightInPixels, { fit: "fill" }).toBuffer();
|
|
93
|
+
const composed = await sharp(background).composite([{
|
|
94
|
+
input: foreground,
|
|
95
|
+
left: geometry.offsetXInPixels,
|
|
96
|
+
top: geometry.offsetYInPixels
|
|
97
|
+
}]).png().toBuffer();
|
|
98
|
+
return new Uint8Array(composed);
|
|
99
|
+
}
|
|
100
|
+
async function importSharp() {
|
|
101
|
+
try {
|
|
102
|
+
const sharpModule = await import("sharp");
|
|
103
|
+
const factory = sharpModule.default;
|
|
104
|
+
return factory;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
'fitScreenshotToCanvas needs the optional peer dependency "sharp". Install it in the consuming project (npm i -D sharp).',
|
|
108
|
+
{ cause: error }
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function roundToMatchingParity(value, target) {
|
|
113
|
+
const rounded = Math.round(value);
|
|
114
|
+
if ((target - rounded) % MARGIN_SIDES === 0) {
|
|
115
|
+
return rounded;
|
|
116
|
+
}
|
|
117
|
+
return value >= rounded ? rounded + 1 : rounded - 1;
|
|
118
|
+
}
|
|
119
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
120
|
+
0 && (module.exports = {
|
|
121
|
+
computeFitToCanvas,
|
|
122
|
+
fitScreenshotToCanvas
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2ZpdC1zY3JlZW5zaG90LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogRml0cyBhIHNjcmVlbnNob3Qgb250byBhIGNhbnZhcyBvZiBhIGRpZmZlcmVudCBhc3BlY3QgcmF0aW8gd2l0aG91dCBjcm9wcGluZ1xuICogaXQgb3IgZGlzdG9ydGluZyBpdCwgZmlsbGluZyB0aGUgbGVmdG92ZXIgbWFyZ2lucyB3aXRoIGEgYmx1cnJlZCwgZW5sYXJnZWRcbiAqIGNvcHkgb2YgdGhlIHNhbWUgaW1hZ2UgKHRoZSBcInBpbGxhcmJveFwiIHRyZWF0bWVudCB1c2VkIGJ5IHN0b3JlIGxpc3RpbmdzKS5cbiAqXG4gKiBUaGUgbW90aXZhdGluZyBjYXNlIGlzIGEgbW9iaWxlIHN0b3JlIHNjcmVlbnNob3QuIFRoZSBBbmRyb2lkIGVtdWxhdG9yJ3NcbiAqIGZyYW1lYnVmZmVyIGlzIHdoYXRldmVyIHRoZSBBVkQncyBzY3JlZW4gaXMgXHUyMDE0IGEgUGl4ZWwgMTAgUHJvIFhMIGlzIDEzNDR4Mjk5MixcbiAqIHJvdWdobHkgOToyMCBcdTIwMTQgd2hpbGUgdGhlIGNvbW11bml0eSBzdG9yZSBhc2tzIGZvciA5MDB4MTYwMCAoOToxNikuIENyb3BwaW5nXG4gKiB0byA5OjE2IHRocm93cyBhd2F5IGEgZmlmdGggb2YgdGhlIGZyYW1lLCBhbmQgc3RyZXRjaGluZyBkaXN0b3J0cyB0aGUgVUksIHNvXG4gKiB0aGUgaW1hZ2UgaXMgc2NhbGVkIHRvIGZpdCB0aGUgSEVJR0hUIGFuZCB0aGUgdHdvIHNpZGUgbWFyZ2lucyBhcmUgZmlsbGVkLlxuICpcbiAqIFRoZSBnZW9tZXRyeSBpcyBhIHB1cmUgZnVuY3Rpb24gc28gaXQgY2FuIGJlIHVuaXQtdGVzdGVkOyB0aGUgcGl4ZWwgd29yayBuZWVkc1xuICogYHNoYXJwYCwgd2hpY2ggaXMgYW4gT1BUSU9OQUwgcGVlciBkZXBlbmRlbmN5IFx1MjAxNCBkZWNsYXJlZCByYXRoZXIgdGhhbiBidW5kbGVkXG4gKiBiZWNhdXNlIG9ubHkgc2NyZWVuc2hvdCBjYXB0dXJlIG5lZWRzIGl0LCBhbmQgaXQgc2hpcHMgcGxhdGZvcm0tc3BlY2lmaWNcbiAqIG5hdGl2ZSBiaW5hcmllcyB0aGF0IGV2ZXJ5IG90aGVyIGNvbnN1bWVyIHdvdWxkIHBheSBmb3IuXG4gKi9cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciB7QGxpbmsgY29tcHV0ZUZpdFRvQ2FudmFzfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb21wdXRlRml0VG9DYW52YXNQYXJhbXMge1xuICAvKipcbiAgICogSGVpZ2h0IG9mIHRoZSB0YXJnZXQgY2FudmFzLCBpbiBwaXhlbHMuXG4gICAqL1xuICByZWFkb25seSBjYW52YXNIZWlnaHRJblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBXaWR0aCBvZiB0aGUgdGFyZ2V0IGNhbnZhcywgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgY2FudmFzV2lkdGhJblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBIZWlnaHQgb2YgdGhlIHNvdXJjZSBpbWFnZSwgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgc291cmNlSGVpZ2h0SW5QaXhlbHM6IG51bWJlcjtcblxuICAvKipcbiAgICogV2lkdGggb2YgdGhlIHNvdXJjZSBpbWFnZSwgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgc291cmNlV2lkdGhJblBpeGVsczogbnVtYmVyO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGluayBmaXRTY3JlZW5zaG90VG9DYW52YXN9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZpdFNjcmVlbnNob3RUb0NhbnZhc09wdGlvbnMge1xuICAvKipcbiAgICogR2F1c3NpYW4gYmx1ciBzdHJlbmd0aCBhcHBsaWVkIHRvIHRoZSBtYXJnaW4gZmlsbC5cbiAgICpcbiAgICogQGRlZmF1bHQgYDI0YFxuICAgKi9cbiAgcmVhZG9ubHkgYmx1clNpZ21hPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBIZWlnaHQgb2YgdGhlIHRhcmdldCBjYW52YXMsIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IGNhbnZhc0hlaWdodEluUGl4ZWxzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFdpZHRoIG9mIHRoZSB0YXJnZXQgY2FudmFzLCBpbiBwaXhlbHMuXG4gICAqL1xuICByZWFkb25seSBjYW52YXNXaWR0aEluUGl4ZWxzOiBudW1iZXI7XG59XG5cbi8qKlxuICogV2hlcmUgdGhlIHNjYWxlZCBzb3VyY2UgaW1hZ2Ugc2l0cyBvbiB0aGUgY2FudmFzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZpdFRvQ2FudmFzR2VvbWV0cnkge1xuICAvKipcbiAgICogV2lkdGggb2YgZWFjaCBzaWRlIG1hcmdpbiwgaW4gcGl4ZWxzLiBCb3RoIHNpZGVzIGFyZSBlcXVhbCBieSBjb25zdHJ1Y3Rpb24uXG4gICAqL1xuICByZWFkb25seSBtYXJnaW5JblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBMZWZ0IG9mZnNldCBvZiB0aGUgc2NhbGVkIGltYWdlIG9uIHRoZSBjYW52YXMsIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IG9mZnNldFhJblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUb3Agb2Zmc2V0IG9mIHRoZSBzY2FsZWQgaW1hZ2Ugb24gdGhlIGNhbnZhcywgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgb2Zmc2V0WUluUGl4ZWxzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEhlaWdodCB0aGUgc291cmNlIGlzIHNjYWxlZCB0bywgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgc2NhbGVkSGVpZ2h0SW5QaXhlbHM6IG51bWJlcjtcblxuICAvKipcbiAgICogV2lkdGggdGhlIHNvdXJjZSBpcyBzY2FsZWQgdG8sIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IHNjYWxlZFdpZHRoSW5QaXhlbHM6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBBIGxheWVyIHBhc3NlZCB0byBgc2hhcnBgJ3MgYGNvbXBvc2l0ZWAuXG4gKi9cbmludGVyZmFjZSBTaGFycENvbXBvc2l0ZUxheWVyIHtcbiAgcmVhZG9ubHkgaW5wdXQ6IEJ1ZmZlcjtcbiAgcmVhZG9ubHkgbGVmdDogbnVtYmVyO1xuICByZWFkb25seSB0b3A6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBUaGUgYHNoYXJwYCBlbnRyeSBwb2ludCB0aGlzIG1vZHVsZSB1c2VzLCBkZXNjcmliZWQgc3RydWN0dXJhbGx5IHNvIHRoZSBtb2R1bGVcbiAqIHR5cGUtY2hlY2tzIGFnYWluc3QgdGhlIG9wdGlvbmFsIHBlZXIgcmF0aGVyIHRoYW4gZGVwZW5kaW5nIG9uIGl0cyB0eXBlcy5cbiAqL1xudHlwZSBTaGFycEZhY3RvcnkgPSAoaW5wdXQ6IFVpbnQ4QXJyYXkpID0+IFNoYXJwSW5zdGFuY2U7XG5cbi8qKlxuICogT25lIGBzaGFycGAgcGlwZWxpbmUuXG4gKi9cbmludGVyZmFjZSBTaGFycEluc3RhbmNlIHtcbiAgYmx1cih0aGlzOiB2b2lkLCBzaWdtYTogbnVtYmVyKTogU2hhcnBJbnN0YW5jZTtcbiAgY29tcG9zaXRlKHRoaXM6IHZvaWQsIGxheWVyczogU2hhcnBDb21wb3NpdGVMYXllcltdKTogU2hhcnBJbnN0YW5jZTtcbiAgbWV0YWRhdGEodGhpczogdm9pZCk6IFByb21pc2U8U2hhcnBNZXRhZGF0YT47XG4gIHBuZyh0aGlzOiB2b2lkKTogU2hhcnBJbnN0YW5jZTtcbiAgcmVzaXplKHRoaXM6IHZvaWQsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBvcHRpb25zPzogU2hhcnBSZXNpemVPcHRpb25zKTogU2hhcnBJbnN0YW5jZTtcbiAgdG9CdWZmZXIodGhpczogdm9pZCk6IFByb21pc2U8QnVmZmVyPjtcbn1cblxuLyoqXG4gKiBUaGUgc3Vic2V0IG9mIGBzaGFycGAncyBtZXRhZGF0YSB0aGlzIG1vZHVsZSByZWFkcy5cbiAqL1xuaW50ZXJmYWNlIFNoYXJwTWV0YWRhdGEge1xuICByZWFkb25seSBoZWlnaHQ/OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIHJlYWRvbmx5IHdpZHRoPzogbnVtYmVyIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFRoZSBzdWJzZXQgb2YgYHNoYXJwYCdzIHJlc2l6ZSBvcHRpb25zIHRoaXMgbW9kdWxlIHNldHMuXG4gKi9cbmludGVyZmFjZSBTaGFycFJlc2l6ZU9wdGlvbnMge1xuICByZWFkb25seSBmaXQ6ICdjb3ZlcicgfCAnZmlsbCc7XG59XG5cbi8qKlxuICogRGVmYXVsdCBHYXVzc2lhbiBibHVyIHN0cmVuZ3RoIGZvciB0aGUgbWFyZ2luIGZpbGw6IHNvZnQgZW5vdWdoIHRoYXQgbm9cbiAqIGRldGFpbCByZWFkcyBhcyBjb250ZW50LCBnZW50bGUgZW5vdWdoIHRvIGtlZXAgdGhlIGZyYW1lJ3MgY29sb3JzLlxuICovXG5jb25zdCBERUZBVUxUX0JMVVJfU0lHTUEgPSAyNDtcblxuLyoqXG4gKiBUaGUgbnVtYmVyIG9mIHNpZGUgbWFyZ2lucyB0aGUgbGVmdG92ZXIgd2lkdGggaXMgc3BsaXQgYmV0d2Vlbi5cbiAqL1xuY29uc3QgTUFSR0lOX1NJREVTID0gMjtcblxuLyoqXG4gKiBDb21wdXRlcyBob3cgYSBzb3VyY2UgaW1hZ2UgaXMgc2NhbGVkIGFuZCBwbGFjZWQgdG8gZmlsbCBhIGNhbnZhcydzIGhlaWdodCxcbiAqIHdpdGggZXF1YWwgbWFyZ2lucyBvbiB0aGUgbGVmdCBhbmQgcmlnaHQuXG4gKlxuICogVGhlIHNjYWxlZCB3aWR0aCBpcyByb3VuZGVkIHRvIHRoZSBuZWFyZXN0IGludGVnZXIgdGhhdCBsZWF2ZXMgYW4gRVZFTlxuICogcmVtYWluZGVyLCBzbyB0aGUgdHdvIG1hcmdpbnMgYXJlIGV4YWN0bHkgZXF1YWwgXHUyMDE0IGFuIGFzeW1tZXRyaWMgcGlsbGFyYm94IGlzXG4gKiB2aXNpYmxlIGF0IGEgZ2xhbmNlIGFuZCBsb29rcyBsaWtlIGEgbWlzdGFrZS4gV2hlcmUgYm90aCBuZWlnaGJvcnMgcXVhbGlmeSxcbiAqIHRoZSBvbmUgY2xvc2VyIHRvIHRoZSB0cnVlIHNjYWxlZCB3aWR0aCB3aW5zLCBzbyB0aGUgYXNwZWN0IGVycm9yIHN0YXlzIGJlbG93XG4gKiBvbmUgcGFydCBpbiBhIHRob3VzYW5kLlxuICpcbiAqIFdvcmtlZCBleGFtcGxlLCB0aGUgbW9iaWxlIHN0b3JlIGNhc2U6IGEgMTM0NHgyOTkyIGZyYW1lIG9udG8gYSA5MDB4MTYwMFxuICogY2FudmFzIHNjYWxlcyBieSBgMTYwMC8yOTkyYCB0byA3MTguNzIgd2lkZS4gNzE5IHdvdWxkIGxlYXZlIGEgMTgxcHhcbiAqIHJlbWFpbmRlciwgd2hpY2ggY2Fubm90IHNwbGl0IGV2ZW5seSwgc28gNzE4IGlzIGNob3NlbiAobWFyZ2luIDkxKSBvdmVyIDcyMFxuICogKG1hcmdpbiA5MCkgYmVjYXVzZSA3MTggaXMgbmVhcmVyIDcxOC43Mi5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHNvdXJjZSBhbmQgY2FudmFzIGRpbWVuc2lvbnMuXG4gKiBAcmV0dXJucyBUaGUgc2NhbGVkIHNpemUsIHRoZSBvZmZzZXRzLCBhbmQgdGhlIHNpZGUgbWFyZ2luLlxuICogQHRocm93cyBFcnJvciBpZiBhbnkgZGltZW5zaW9uIGlzIG5vdCBhIHBvc2l0aXZlIG51bWJlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXB1dGVGaXRUb0NhbnZhcyhwYXJhbXM6IENvbXB1dGVGaXRUb0NhbnZhc1BhcmFtcyk6IEZpdFRvQ2FudmFzR2VvbWV0cnkge1xuICBjb25zdCB7XG4gICAgY2FudmFzSGVpZ2h0SW5QaXhlbHMsXG4gICAgY2FudmFzV2lkdGhJblBpeGVscyxcbiAgICBzb3VyY2VIZWlnaHRJblBpeGVscyxcbiAgICBzb3VyY2VXaWR0aEluUGl4ZWxzXG4gIH0gPSBwYXJhbXM7XG5cbiAgY29uc3QgbmFtZWREaW1lbnNpb25zOiBbc3RyaW5nLCBudW1iZXJdW10gPSBbXG4gICAgWydjYW52YXNIZWlnaHRJblBpeGVscycsIGNhbnZhc0hlaWdodEluUGl4ZWxzXSxcbiAgICBbJ2NhbnZhc1dpZHRoSW5QaXhlbHMnLCBjYW52YXNXaWR0aEluUGl4ZWxzXSxcbiAgICBbJ3NvdXJjZUhlaWdodEluUGl4ZWxzJywgc291cmNlSGVpZ2h0SW5QaXhlbHNdLFxuICAgIFsnc291cmNlV2lkdGhJblBpeGVscycsIHNvdXJjZVdpZHRoSW5QaXhlbHNdXG4gIF07XG5cbiAgZm9yIChjb25zdCBbbmFtZSwgdmFsdWVdIG9mIG5hbWVkRGltZW5zaW9ucykge1xuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKHZhbHVlKSB8fCB2YWx1ZSA8PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGNvbXB1dGVGaXRUb0NhbnZhczogJHtuYW1lfSBtdXN0IGJlIGEgcG9zaXRpdmUgbnVtYmVyLCBnb3QgJHtTdHJpbmcodmFsdWUpfS5gKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBzY2FsZWRIZWlnaHRJblBpeGVscyA9IGNhbnZhc0hlaWdodEluUGl4ZWxzO1xuICBjb25zdCBleGFjdFNjYWxlZFdpZHRoID0gc291cmNlV2lkdGhJblBpeGVscyAqIChjYW52YXNIZWlnaHRJblBpeGVscyAvIHNvdXJjZUhlaWdodEluUGl4ZWxzKTtcbiAgY29uc3Qgc2NhbGVkV2lkdGhJblBpeGVscyA9IHJvdW5kVG9NYXRjaGluZ1Bhcml0eShleGFjdFNjYWxlZFdpZHRoLCBjYW52YXNXaWR0aEluUGl4ZWxzKTtcblxuICBpZiAoc2NhbGVkV2lkdGhJblBpeGVscyA+IGNhbnZhc1dpZHRoSW5QaXhlbHMpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnY29tcHV0ZUZpdFRvQ2FudmFzOiB0aGUgc291cmNlIGlzIHdpZGVyIHRoYW4gdGhlIGNhbnZhcyBvbmNlIHNjYWxlZCB0byBpdHMgaGVpZ2h0ICdcbiAgICAgICAgKyBgKCR7U3RyaW5nKHNjYWxlZFdpZHRoSW5QaXhlbHMpfSA+ICR7U3RyaW5nKGNhbnZhc1dpZHRoSW5QaXhlbHMpfSk7IHRoaXMgZml0cyBieSBoZWlnaHQgYW5kIGNhbm5vdCBsZXR0ZXJib3guYFxuICAgICk7XG4gIH1cblxuICBjb25zdCBtYXJnaW5JblBpeGVscyA9IChjYW52YXNXaWR0aEluUGl4ZWxzIC0gc2NhbGVkV2lkdGhJblBpeGVscykgLyBNQVJHSU5fU0lERVM7XG5cbiAgcmV0dXJuIHtcbiAgICBtYXJnaW5JblBpeGVscyxcbiAgICBvZmZzZXRYSW5QaXhlbHM6IG1hcmdpbkluUGl4ZWxzLFxuICAgIG9mZnNldFlJblBpeGVsczogMCxcbiAgICBzY2FsZWRIZWlnaHRJblBpeGVscyxcbiAgICBzY2FsZWRXaWR0aEluUGl4ZWxzXG4gIH07XG59XG5cbi8qKlxuICogU2NhbGVzIGEgc2NyZWVuc2hvdCB0byBmaWxsIGEgY2FudmFzJ3MgaGVpZ2h0IGFuZCBmaWxscyB0aGUgc2lkZSBtYXJnaW5zIHdpdGhcbiAqIGEgYmx1cnJlZCwgZW5sYXJnZWQgY29weSBvZiB0aGUgc2FtZSBpbWFnZS5cbiAqXG4gKiBOb3RoaW5nIGlzIGNyb3BwZWQgYW5kIG5vdGhpbmcgaXMgc3RyZXRjaGVkOiB0aGUgdmlzaWJsZSBzY3JlZW5zaG90IGtlZXBzIGl0c1xuICogYXNwZWN0IHJhdGlvIHRvIHdpdGhpbiBhIHJvdW5kaW5nIHBpeGVsLCBhbmQgdGhlIG1hcmdpbnMgYXJlIG1hZGUgb2YgdGhlXG4gKiBpbWFnZSBpdHNlbGYgcmF0aGVyIHRoYW4gYSBmbGF0IGNvbG9yLCBzbyB0aGUgcmVzdWx0IHJlYWRzIGFzIG9uZSBmcmFtZS5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgLSBUaGUgc291cmNlIFBORy5cbiAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIHRhcmdldCBjYW52YXMgc2l6ZSBhbmQgYmx1ciBzdHJlbmd0aC5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNvbXBvc2VkIFBORywgZXhhY3RseSB0aGUgY2FudmFzIHNpemUuXG4gKiBAdGhyb3dzIEVycm9yIGlmIGBzaGFycGAgaXMgbm90IGluc3RhbGxlZCwgb3IgdGhlIHNvdXJjZSBkaW1lbnNpb25zIGNhbm5vdCBiZSByZWFkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZml0U2NyZWVuc2hvdFRvQ2FudmFzKGJ5dGVzOiBVaW50OEFycmF5LCBvcHRpb25zOiBGaXRTY3JlZW5zaG90VG9DYW52YXNPcHRpb25zKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIGNvbnN0IHtcbiAgICBibHVyU2lnbWEgPSBERUZBVUxUX0JMVVJfU0lHTUEsXG4gICAgY2FudmFzSGVpZ2h0SW5QaXhlbHMsXG4gICAgY2FudmFzV2lkdGhJblBpeGVsc1xuICB9ID0gb3B0aW9ucztcblxuICBjb25zdCBzaGFycCA9IGF3YWl0IGltcG9ydFNoYXJwKCk7XG4gIGNvbnN0IG1ldGFkYXRhID0gYXdhaXQgc2hhcnAoYnl0ZXMpLm1ldGFkYXRhKCk7XG4gIGNvbnN0IHNvdXJjZVdpZHRoSW5QaXhlbHMgPSBtZXRhZGF0YS53aWR0aDtcbiAgY29uc3Qgc291cmNlSGVpZ2h0SW5QaXhlbHMgPSBtZXRhZGF0YS5oZWlnaHQ7XG5cbiAgLyogdjggaWdub3JlIG5leHQgMyAtLSBEZWZlbnNpdmU6IGBzaGFycGAgcmVqZWN0cyBhIG5vbi1pbWFnZSBiZWZvcmUgaXQgY2FuIHJlcG9ydCBtZXRhZGF0YSB3aXRob3V0IGRpbWVuc2lvbnMsIHNvIHRoaXMgYnJhbmNoIGlzIHVucmVhY2hhYmxlIGZyb20gYSB0ZXN0LiAqL1xuICBpZiAoc291cmNlV2lkdGhJblBpeGVscyA9PT0gdW5kZWZpbmVkIHx8IHNvdXJjZUhlaWdodEluUGl4ZWxzID09PSB1bmRlZmluZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ZpdFNjcmVlbnNob3RUb0NhbnZhczogY291bGQgbm90IHJlYWQgdGhlIHNvdXJjZSBpbWFnZSBkaW1lbnNpb25zLicpO1xuICB9XG5cbiAgY29uc3QgZ2VvbWV0cnkgPSBjb21wdXRlRml0VG9DYW52YXMoe1xuICAgIGNhbnZhc0hlaWdodEluUGl4ZWxzLFxuICAgIGNhbnZhc1dpZHRoSW5QaXhlbHMsXG4gICAgc291cmNlSGVpZ2h0SW5QaXhlbHMsXG4gICAgc291cmNlV2lkdGhJblBpeGVsc1xuICB9KTtcblxuICAvLyBUaGUgYmFja2dyb3VuZCBpcyB0aGUgc2FtZSBmcmFtZSBibG93biB1cCB0byBDT1ZFUiB0aGUgY2FudmFzIGFuZCBibHVycmVkLFxuICAvLyBTbyB0aGUgbWFyZ2lucyBjYXJyeSB0aGUgc2NyZWVuc2hvdCdzIG93biBjb2xvcnMgaW5zdGVhZCBvZiBhIGZsYXQgYmFyLlxuICBjb25zdCBiYWNrZ3JvdW5kID0gYXdhaXQgc2hhcnAoYnl0ZXMpXG4gICAgLnJlc2l6ZShjYW52YXNXaWR0aEluUGl4ZWxzLCBjYW52YXNIZWlnaHRJblBpeGVscywgeyBmaXQ6ICdjb3ZlcicgfSlcbiAgICAuYmx1cihibHVyU2lnbWEpXG4gICAgLnRvQnVmZmVyKCk7XG5cbiAgY29uc3QgZm9yZWdyb3VuZCA9IGF3YWl0IHNoYXJwKGJ5dGVzKVxuICAgIC5yZXNpemUoZ2VvbWV0cnkuc2NhbGVkV2lkdGhJblBpeGVscywgZ2VvbWV0cnkuc2NhbGVkSGVpZ2h0SW5QaXhlbHMsIHsgZml0OiAnZmlsbCcgfSlcbiAgICAudG9CdWZmZXIoKTtcblxuICBjb25zdCBjb21wb3NlZCA9IGF3YWl0IHNoYXJwKGJhY2tncm91bmQpXG4gICAgLmNvbXBvc2l0ZShbe1xuICAgICAgaW5wdXQ6IGZvcmVncm91bmQsXG4gICAgICBsZWZ0OiBnZW9tZXRyeS5vZmZzZXRYSW5QaXhlbHMsXG4gICAgICB0b3A6IGdlb21ldHJ5Lm9mZnNldFlJblBpeGVsc1xuICAgIH1dKVxuICAgIC5wbmcoKVxuICAgIC50b0J1ZmZlcigpO1xuXG4gIHJldHVybiBuZXcgVWludDhBcnJheShjb21wb3NlZCk7XG59XG5cbi8qKlxuICogTG9hZHMgYHNoYXJwYCBvbiBkZW1hbmQsIHNvIGltcG9ydGluZyB0aGlzIG1vZHVsZSBkb2VzIG5vdCByZXF1aXJlIGl0LlxuICpcbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGBzaGFycGAgZmFjdG9yeS5cbiAqIEB0aHJvd3MgRXJyb3IgbmFtaW5nIHRoZSBtaXNzaW5nIG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jeS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaW1wb3J0U2hhcnAoKTogUHJvbWlzZTxTaGFycEZhY3Rvcnk+IHtcbiAgdHJ5IHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmVzdHJpY3RlZC1zeW50YXggLS0gYHNoYXJwYCBpcyBhbiBPUFRJT05BTCBwZWVyLCBzbyBpdCBtdXN0IGJlIGxvYWRlZCBsYXppbHk6IGEgc3RhdGljIGltcG9ydCB3b3VsZCBkcmFnIGl0cyBuYXRpdmUgYmluYXJpZXMgaW50byBldmVyeSBjb25zdW1lciBvZiB0aGlzIHBhY2thZ2UncyBpbmRleC5cbiAgICBjb25zdCBzaGFycE1vZHVsZSA9IGF3YWl0IGltcG9ydCgnc2hhcnAnKTtcbiAgICBjb25zdCBmYWN0b3J5OiB1bmtub3duID0gc2hhcnBNb2R1bGUuZGVmYXVsdDtcbiAgICByZXR1cm4gZmFjdG9yeSBhcyBTaGFycEZhY3Rvcnk7XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgLyogdjggaWdub3JlIHN0YXJ0IC0tIFJlYWNoZWQgb25seSB3aGVuIHRoZSBvcHRpb25hbCBwZWVyIGlzIGFic2VudCwgd2hpY2ggaXQgbmV2ZXIgaXMgaW4gdGhpcyBwYWNrYWdlJ3Mgb3duIHRlc3QgcnVuLiAqL1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdmaXRTY3JlZW5zaG90VG9DYW52YXMgbmVlZHMgdGhlIG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jeSBcInNoYXJwXCIuICdcbiAgICAgICAgKyAnSW5zdGFsbCBpdCBpbiB0aGUgY29uc3VtaW5nIHByb2plY3QgKG5wbSBpIC1EIHNoYXJwKS4nLFxuICAgICAgeyBjYXVzZTogZXJyb3IgfVxuICAgICk7XG4gICAgLyogdjggaWdub3JlIHN0b3AgKi9cbiAgfVxufVxuXG4vKipcbiAqIFJvdW5kcyBhIHdpZHRoIHRvIHRoZSBuZWFyZXN0IGludGVnZXIgc2hhcmluZyBgdGFyZ2V0YCdzIHBhcml0eSwgc29cbiAqIGB0YXJnZXQgLSByZXN1bHRgIGlzIGV2ZW4gYW5kIHNwbGl0cyBpbnRvIHR3byBlcXVhbCBtYXJnaW5zLlxuICpcbiAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBleGFjdCBzY2FsZWQgd2lkdGguXG4gKiBAcGFyYW0gdGFyZ2V0IC0gVGhlIGNhbnZhcyB3aWR0aCB3aG9zZSBwYXJpdHkgbXVzdCBiZSBtYXRjaGVkLlxuICogQHJldHVybnMgVGhlIG5lYXJlc3QgaW50ZWdlciBvZiB0aGUgc2FtZSBwYXJpdHkgYXMgYHRhcmdldGAuXG4gKi9cbmZ1bmN0aW9uIHJvdW5kVG9NYXRjaGluZ1Bhcml0eSh2YWx1ZTogbnVtYmVyLCB0YXJnZXQ6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0IHJvdW5kZWQgPSBNYXRoLnJvdW5kKHZhbHVlKTtcbiAgaWYgKCh0YXJnZXQgLSByb3VuZGVkKSAlIE1BUkdJTl9TSURFUyA9PT0gMCkge1xuICAgIHJldHVybiByb3VuZGVkO1xuICB9XG5cbiAgLy8gYHJvdW5kZWRgIGxlYXZlcyBhbiBvZGQgcmVtYWluZGVyLCBzbyBzdGVwIHRvIHdoaWNoZXZlciBuZWlnaGJvciBpcyBjbG9zZXJcbiAgLy8gVG8gdGhlIHRydWUgdmFsdWU7IGJvdGggaGF2ZSB0aGUgcGFyaXR5IGByb3VuZGVkYCBsYWNrcy5cbiAgcmV0dXJuIHZhbHVlID49IHJvdW5kZWQgPyByb3VuZGVkICsgMSA6IHJvdW5kZWQgLSAxO1xufVxuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQThJQSxNQUFNLHFCQUFxQjtBQUszQixNQUFNLGVBQWU7QUFxQmQsU0FBUyxtQkFBbUIsUUFBdUQ7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
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Fits a screenshot onto a canvas of a different aspect ratio without cropping
|
|
5
|
+
* it or distorting it, filling the leftover margins with a blurred, enlarged
|
|
6
|
+
* copy of the same image (the "pillarbox" treatment used by store listings).
|
|
7
|
+
*
|
|
8
|
+
* The motivating case is a mobile store screenshot. The Android emulator's
|
|
9
|
+
* framebuffer is whatever the AVD's screen is — a Pixel 10 Pro XL is 1344x2992,
|
|
10
|
+
* roughly 9:20 — while the community store asks for 900x1600 (9:16). Cropping
|
|
11
|
+
* to 9:16 throws away a fifth of the frame, and stretching distorts the UI, so
|
|
12
|
+
* the image is scaled to fit the HEIGHT and the two side margins are filled.
|
|
13
|
+
*
|
|
14
|
+
* The geometry is a pure function so it can be unit-tested; the pixel work needs
|
|
15
|
+
* `sharp`, which is an OPTIONAL peer dependency — declared rather than bundled
|
|
16
|
+
* because only screenshot capture needs it, and it ships platform-specific
|
|
17
|
+
* native binaries that every other consumer would pay for.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Parameters for {@link computeFitToCanvas}.
|
|
21
|
+
*/
|
|
22
|
+
export interface ComputeFitToCanvasParams {
|
|
23
|
+
/**
|
|
24
|
+
* Height of the target canvas, in pixels.
|
|
25
|
+
*/
|
|
26
|
+
readonly canvasHeightInPixels: number;
|
|
27
|
+
/**
|
|
28
|
+
* Width of the target canvas, in pixels.
|
|
29
|
+
*/
|
|
30
|
+
readonly canvasWidthInPixels: number;
|
|
31
|
+
/**
|
|
32
|
+
* Height of the source image, in pixels.
|
|
33
|
+
*/
|
|
34
|
+
readonly sourceHeightInPixels: number;
|
|
35
|
+
/**
|
|
36
|
+
* Width of the source image, in pixels.
|
|
37
|
+
*/
|
|
38
|
+
readonly sourceWidthInPixels: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Options for {@link fitScreenshotToCanvas}.
|
|
42
|
+
*/
|
|
43
|
+
export interface FitScreenshotToCanvasOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Gaussian blur strength applied to the margin fill.
|
|
46
|
+
*
|
|
47
|
+
* @default `24`
|
|
48
|
+
*/
|
|
49
|
+
readonly blurSigma?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Height of the target canvas, in pixels.
|
|
52
|
+
*/
|
|
53
|
+
readonly canvasHeightInPixels: number;
|
|
54
|
+
/**
|
|
55
|
+
* Width of the target canvas, in pixels.
|
|
56
|
+
*/
|
|
57
|
+
readonly canvasWidthInPixels: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Where the scaled source image sits on the canvas.
|
|
61
|
+
*/
|
|
62
|
+
export interface FitToCanvasGeometry {
|
|
63
|
+
/**
|
|
64
|
+
* Width of each side margin, in pixels. Both sides are equal by construction.
|
|
65
|
+
*/
|
|
66
|
+
readonly marginInPixels: number;
|
|
67
|
+
/**
|
|
68
|
+
* Left offset of the scaled image on the canvas, in pixels.
|
|
69
|
+
*/
|
|
70
|
+
readonly offsetXInPixels: number;
|
|
71
|
+
/**
|
|
72
|
+
* Top offset of the scaled image on the canvas, in pixels.
|
|
73
|
+
*/
|
|
74
|
+
readonly offsetYInPixels: number;
|
|
75
|
+
/**
|
|
76
|
+
* Height the source is scaled to, in pixels.
|
|
77
|
+
*/
|
|
78
|
+
readonly scaledHeightInPixels: number;
|
|
79
|
+
/**
|
|
80
|
+
* Width the source is scaled to, in pixels.
|
|
81
|
+
*/
|
|
82
|
+
readonly scaledWidthInPixels: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Computes how a source image is scaled and placed to fill a canvas's height,
|
|
86
|
+
* with equal margins on the left and right.
|
|
87
|
+
*
|
|
88
|
+
* The scaled width is rounded to the nearest integer that leaves an EVEN
|
|
89
|
+
* remainder, so the two margins are exactly equal — an asymmetric pillarbox is
|
|
90
|
+
* visible at a glance and looks like a mistake. Where both neighbors qualify,
|
|
91
|
+
* the one closer to the true scaled width wins, so the aspect error stays below
|
|
92
|
+
* one part in a thousand.
|
|
93
|
+
*
|
|
94
|
+
* Worked example, the mobile store case: a 1344x2992 frame onto a 900x1600
|
|
95
|
+
* canvas scales by `1600/2992` to 718.72 wide. 719 would leave a 181px
|
|
96
|
+
* remainder, which cannot split evenly, so 718 is chosen (margin 91) over 720
|
|
97
|
+
* (margin 90) because 718 is nearer 718.72.
|
|
98
|
+
*
|
|
99
|
+
* @param params - The source and canvas dimensions.
|
|
100
|
+
* @returns The scaled size, the offsets, and the side margin.
|
|
101
|
+
* @throws Error if any dimension is not a positive number.
|
|
102
|
+
*/
|
|
103
|
+
export declare function computeFitToCanvas(params: ComputeFitToCanvasParams): FitToCanvasGeometry;
|
|
104
|
+
/**
|
|
105
|
+
* Scales a screenshot to fill a canvas's height and fills the side margins with
|
|
106
|
+
* a blurred, enlarged copy of the same image.
|
|
107
|
+
*
|
|
108
|
+
* Nothing is cropped and nothing is stretched: the visible screenshot keeps its
|
|
109
|
+
* aspect ratio to within a rounding pixel, and the margins are made of the
|
|
110
|
+
* image itself rather than a flat color, so the result reads as one frame.
|
|
111
|
+
*
|
|
112
|
+
* @param bytes - The source PNG.
|
|
113
|
+
* @param options - The target canvas size and blur strength.
|
|
114
|
+
* @returns A {@link Promise} that resolves to the composed PNG, exactly the canvas size.
|
|
115
|
+
* @throws Error if `sharp` is not installed, or the source dimensions cannot be read.
|
|
116
|
+
*/
|
|
117
|
+
export declare function fitScreenshotToCanvas(bytes: Uint8Array, options: FitScreenshotToCanvasOptions): Promise<Uint8Array>;
|
package/dist/lib/cjs/index.cjs
CHANGED
|
@@ -31,10 +31,12 @@ __export(index_exports, {
|
|
|
31
31
|
buildDemoVaultPopulate: () => import_demo_vault_populate.buildDemoVaultPopulate,
|
|
32
32
|
buildDeviceMetricsOverride: () => import_capture_screenshot.buildDeviceMetricsOverride,
|
|
33
33
|
captureObsidianScreenshot: () => import_capture_obsidian_screenshot.captureObsidianScreenshot,
|
|
34
|
+
computeFitToCanvas: () => import_fit_screenshot.computeFitToCanvas,
|
|
34
35
|
connectToCdp: () => import_connect_to_cdp.connectToCdp,
|
|
35
36
|
createTransportFromOptions: () => import_transport_factory.createTransportFromOptions,
|
|
36
37
|
decodeBase64Png: () => import_capture_screenshot.decodeBase64Png,
|
|
37
38
|
evalInObsidian: () => import_eval_in_obsidian.evalInObsidian,
|
|
39
|
+
fitScreenshotToCanvas: () => import_fit_screenshot.fitScreenshotToCanvas,
|
|
38
40
|
getVersionMetadata: () => import_obsidian_metadata.getVersionMetadata,
|
|
39
41
|
isPng: () => import_capture_screenshot.isPng,
|
|
40
42
|
pollInObsidian: () => import_poll_in_obsidian.pollInObsidian,
|
|
@@ -61,6 +63,7 @@ var import_demo_vault_populate = require("./demo-vault-populate.cjs");
|
|
|
61
63
|
var import_demo_vault_tree = require("./demo-vault-tree.cjs");
|
|
62
64
|
var import_electron_compatibility = require("./electron-compatibility.cjs");
|
|
63
65
|
var import_eval_in_obsidian = require("./eval-in-obsidian.cjs");
|
|
66
|
+
var import_fit_screenshot = require("./fit-screenshot.cjs");
|
|
64
67
|
var import_incompatible_installer_version_error = require("./incompatible-installer-version-error.cjs");
|
|
65
68
|
var import_installer_compatibility = require("./installer-compatibility.cjs");
|
|
66
69
|
var import_lib_registry = require("./lib-registry.cjs");
|
|
@@ -91,10 +94,12 @@ var import_version_matrix = require("./version-matrix.cjs");
|
|
|
91
94
|
buildDemoVaultPopulate,
|
|
92
95
|
buildDeviceMetricsOverride,
|
|
93
96
|
captureObsidianScreenshot,
|
|
97
|
+
computeFitToCanvas,
|
|
94
98
|
connectToCdp,
|
|
95
99
|
createTransportFromOptions,
|
|
96
100
|
decodeBase64Png,
|
|
97
101
|
evalInObsidian,
|
|
102
|
+
fitScreenshotToCanvas,
|
|
98
103
|
getVersionMetadata,
|
|
99
104
|
isPng,
|
|
100
105
|
pollInObsidian,
|
|
@@ -110,4 +115,4 @@ var import_version_matrix = require("./version-matrix.cjs");
|
|
|
110
115
|
setVaultPathResolver,
|
|
111
116
|
unregisterVault
|
|
112
117
|
});
|
|
113
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
118
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2luZGV4LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogQ29udGFpbnMgdGhlIGVudHJ5IHBvaW50IGZvciB0aGUgaW50ZWdyYXRpb24gdGVzdGluZyBtb2R1bGUuXG4gKi9cblxuZXhwb3J0IHR5cGUge1xuICBBc2FyRmFsbGJhY2ssXG4gIEFzYXJGYWxsYmFja1RpZXIsXG4gIFJlc29sdmVBc2FyRmFsbGJhY2tQYXJhbXNcbn0gZnJvbSAnLi9hc2FyLWZhbGxiYWNrLWRldGVjdGlvbi5janMnO1xuZXhwb3J0IHsgcmVzb2x2ZUFzYXJGYWxsYmFjayB9IGZyb20gJy4vYXNhci1mYWxsYmFjay1kZXRlY3Rpb24uY2pzJztcbmV4cG9ydCB0eXBlIHsgQ2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdE9wdGlvbnMgfSBmcm9tICcuL2NhcHR1cmUtb2JzaWRpYW4tc2NyZWVuc2hvdC5janMnO1xuZXhwb3J0IHsgY2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdCB9IGZyb20gJy4vY2FwdHVyZS1vYnNpZGlhbi1zY3JlZW5zaG90LmNqcyc7XG5leHBvcnQgdHlwZSB7XG4gIENhcHR1cmVTY3JlZW5zaG90UGFyYW1zLFxuICBQbmdEaW1lbnNpb25zXG59IGZyb20gJy4vY2FwdHVyZS1zY3JlZW5zaG90LmNqcyc7XG5leHBvcnQge1xuICBidWlsZERldmljZU1ldHJpY3NPdmVycmlkZSxcbiAgZGVjb2RlQmFzZTY0UG5nLFxuICBpc1BuZyxcbiAgcmVhZFBuZ0RpbWVuc2lvbnNcbn0gZnJvbSAnLi9jYXB0dXJlLXNjcmVlbnNob3QuY2pzJztcbmV4cG9ydCB0eXBlIHtcbiAgQ2RwQ29ubmVjdGlvbixcbiAgQ29ubmVjdFRvQ2RwT3B0aW9uc1xufSBmcm9tICcuL2Nvbm5lY3QtdG8tY2RwLmNqcyc7XG5leHBvcnQgeyBjb25uZWN0VG9DZHAgfSBmcm9tICcuL2Nvbm5lY3QtdG8tY2RwLmNqcyc7XG5leHBvcnQgeyBDb250ZXh0SWQgfSBmcm9tICcuL2NvbnRleHQtaWQuY2pzJztcbmV4cG9ydCB0eXBlIHtcbiAgVHJhbnNwb3J0T3B0aW9uc1Jlc29sdmVyLFxuICBWYXVsdFBhdGhSZXNvbHZlclxufSBmcm9tICcuL2NvbnRleHQtcHJvdmlkZXIuY2pzJztcbmV4cG9ydCB7XG4gIHNldFRyYW5zcG9ydE9wdGlvbnNSZXNvbHZlcixcbiAgc2V0VmF1bHRQYXRoUmVzb2x2ZXJcbn0gZnJvbSAnLi9jb250ZXh0LXByb3ZpZGVyLmNqcyc7XG5leHBvcnQgdHlwZSB7XG4gIEJ1aWxkRGVtb1ZhdWx0UG9wdWxhdGVQYXJhbXMsXG4gIEluamVjdFBsdWdpblBhcmFtc1xufSBmcm9tICcuL2RlbW8tdmF1bHQtcG9wdWxhdGUuY2pzJztcbmV4cG9ydCB7IGJ1aWxkRGVtb1ZhdWx0UG9wdWxhdGUgfSBmcm9tICcuL2RlbW8tdmF1bHQtcG9wdWxhdGUuY2pzJztcbmV4cG9ydCB0eXBlIHsgUmVhZERlbW9WYXVsdFRyZWVQYXJhbXMgfSBmcm9tICcuL2RlbW8tdmF1bHQtdHJlZS5janMnO1xuZXhwb3J0IHsgcmVhZERlbW9WYXVsdFRyZWUgfSBmcm9tICcuL2RlbW8tdmF1bHQtdHJlZS5janMnO1xuZXhwb3J0IHR5cGUge1xuICBFbGVjdHJvbkNvbXBhdGliaWxpdHksXG4gIEVsZWN0cm9uQ29tcGF0aWJpbGl0eVRpZXIsXG4gIFJlc29sdmVFbGVjdHJvbkNvbXBhdGliaWxpdHlQYXJhbXNcbn0gZnJvbSAnLi9lbGVjdHJvbi1jb21wYXRpYmlsaXR5LmNqcyc7XG5leHBvcnQgeyByZXNvbHZlRWxlY3Ryb25Db21wYXRpYmlsaXR5IH0gZnJvbSAnLi9lbGVjdHJvbi1jb21wYXRpYmlsaXR5LmNqcyc7XG5leHBvcnQgdHlwZSB7XG4gIEV2YWxJbk9ic2lkaWFuUGFyYW1zLFxuICBIb3ZlckVsZW1lbnRQYXJhbXMsXG4gIExpYixcbiAgTW92ZU1vdXNlUGFyYW1zLFxuICBQcmVzc0tleVBhcmFtcyxcbiAgVHlwZUludG9FZGl0b3JQYXJhbXMsXG4gIFVuaG92ZXJFbGVtZW50UGFyYW1zLFxuICBXYWl0VW50aWxQYXJhbXNcbn0gZnJvbSAnLi9ldmFsLWluLW9ic2lkaWFuLmNqcyc7XG5leHBvcnQgeyBldmFsSW5PYnNpZGlhbiB9IGZyb20gJy4vZXZhbC1pbi1vYnNpZGlhbi5janMnO1xuZXhwb3J0IHR5cGUge1xuICBDb21wdXRlRml0VG9DYW52YXNQYXJhbXMsXG4gIEZpdFNjcmVlbnNob3RUb0NhbnZhc09wdGlvbnMsXG4gIEZpdFRvQ2FudmFzR2VvbWV0cnlcbn0gZnJvbSAnLi9maXQtc2NyZWVuc2hvdC5janMnO1xuZXhwb3J0IHtcbiAgY29tcHV0ZUZpdFRvQ2FudmFzLFxuICBmaXRTY3JlZW5zaG90VG9DYW52YXNcbn0gZnJvbSAnLi9maXQtc2NyZWVuc2hvdC5janMnO1xuZXhwb3J0IHR5cGUgeyBJbmNvbXBhdGlibGVJbnN0YWxsZXJWZXJzaW9uRXJyb3JDb25zdHJ1Y3RvclBhcmFtcyB9IGZyb20gJy4vaW5jb21wYXRpYmxlLWluc3RhbGxlci12ZXJzaW9uLWVycm9yLmNqcyc7XG5leHBvcnQgeyBJbmNvbXBhdGlibGVJbnN0YWxsZXJWZXJzaW9uRXJyb3IgfSBmcm9tICcuL2luY29tcGF0aWJsZS1pbnN0YWxsZXItdmVyc2lvbi1lcnJvci5janMnO1xuZXhwb3J0IHR5cGUge1xuICBJbnN0YWxsZXJDb21wYXRpYmlsaXR5LFxuICBJbnN0YWxsZXJDb21wYXRpYmlsaXR5VGllcixcbiAgUmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHlQYXJhbXNcbn0gZnJvbSAnLi9pbnN0YWxsZXItY29tcGF0aWJpbGl0eS5janMnO1xuZXhwb3J0IHsgcmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHkgfSBmcm9tICcuL2luc3RhbGxlci1jb21wYXRpYmlsaXR5LmNqcyc7XG5leHBvcnQgdHlwZSB7IExpYlJlc29sdmVyIH0gZnJvbSAnLi9saWItcmVnaXN0cnkuY2pzJztcbmV4cG9ydCB7IHJlZ2lzdGVyTGliUmVzb2x2ZXIgfSBmcm9tICcuL2xpYi1yZWdpc3RyeS5janMnO1xuZXhwb3J0IHR5cGUge1xuICBPYnNpZGlhblJ1bnRpbWVWZXJzaW9ucyxcbiAgT2JzaWRpYW5WZXJzaW9uRG93bmxvYWRzLFxuICBPYnNpZGlhblZlcnNpb25NZXRhZGF0YVxufSBmcm9tICcuL29ic2lkaWFuLW1ldGFkYXRhLmNqcyc7XG5leHBvcnQgeyBnZXRWZXJzaW9uTWV0YWRhdGEgfSBmcm9tICcuL29ic2lkaWFuLW1ldGFkYXRhLmNqcyc7XG5leHBvcnQge1xuICBDQVRBTFlTVF9MQVRFU1QsXG4gIFBVQkxJQ19MQVRFU1Rcbn0gZnJvbSAnLi9vYnNpZGlhbi12ZXJzaW9uLmNqcyc7XG5leHBvcnQgdHlwZSB7IFBvbGxJbk9ic2lkaWFuUGFyYW1zIH0gZnJvbSAnLi9wb2xsLWluLW9ic2lkaWFuLmNqcyc7XG5leHBvcnQgeyBwb2xsSW5PYnNpZGlhbiB9IGZyb20gJy4vcG9sbC1pbi1vYnNpZGlhbi5janMnO1xuZXhwb3J0IHsgUmVuZGVyZXJGYWlsZWRUb0luaXRpYWxpemVFcnJvciB9IGZyb20gJy4vcmVuZGVyZXItZmFpbGVkLXRvLWluaXRpYWxpemUtZXJyb3IuY2pzJztcbmV4cG9ydCB0eXBlIHsgUnVuT2JzaWRpYW5WZXJzaW9uTWF0cml4UGFyYW1zIH0gZnJvbSAnLi9ydW4tdmVyc2lvbi1tYXRyaXguY2pzJztcbmV4cG9ydCB7IHJ1bk9ic2lkaWFuVmVyc2lvbk1hdHJpeCB9IGZyb20gJy4vcnVuLXZlcnNpb24tbWF0cml4LmNqcyc7XG5leHBvcnQgdHlwZSB7IFNpbGVudEFzYXJGYWxsYmFja0Vycm9yQ29uc3RydWN0b3JQYXJhbXMgfSBmcm9tICcuL3NpbGVudC1hc2FyLWZhbGxiYWNrLWVycm9yLmNqcyc7XG5leHBvcnQgeyBTaWxlbnRBc2FyRmFsbGJhY2tFcnJvciB9IGZyb20gJy4vc2lsZW50LWFzYXItZmFsbGJhY2stZXJyb3IuY2pzJztcbmV4cG9ydCB0eXBlIHtcbiAgUG9wdWxhdGVGaWxlQ29udGVudCxcbiAgUG9wdWxhdGVGaWxlc1BhcmFtc1xufSBmcm9tICcuL3RlbXBvcmFyeS12YXVsdC5janMnO1xuZXhwb3J0IHsgVGVtcG9yYXJ5VmF1bHQgfSBmcm9tICcuL3RlbXBvcmFyeS12YXVsdC5janMnO1xuZXhwb3J0IHR5cGUge1xuICBBcHBpdW1TZXNzaW9uSW5mbyxcbiAgQXBwaXVtVHJhbnNwb3J0Q29uZmlnXG59IGZyb20gJy4vdHJhbnNwb3J0LWFwcGl1bS5janMnO1xuZXhwb3J0IHsgQXBwaXVtVHJhbnNwb3J0IH0gZnJvbSAnLi90cmFuc3BvcnQtYXBwaXVtLmNqcyc7XG5leHBvcnQgdHlwZSB7XG4gIERlc2t0b3BDZHBUcmFuc3BvcnRDb25maWcsXG4gIE93bmVkSW5zdGFuY2VBc2FyLFxuICBPd25lZEluc3RhbmNlQ29uZmlnXG59IGZyb20gJy4vdHJhbnNwb3J0LWRlc2t0b3AtY2RwLmNqcyc7XG5leHBvcnQgeyBEZXNrdG9wQ2RwVHJhbnNwb3J0IH0gZnJvbSAnLi90cmFuc3BvcnQtZGVza3RvcC1jZHAuY2pzJztcbmV4cG9ydCB7IGNyZWF0ZVRyYW5zcG9ydEZyb21PcHRpb25zIH0gZnJvbSAnLi90cmFuc3BvcnQtZmFjdG9yeS5janMnO1xuZXhwb3J0IHR5cGUge1xuICBPYnNpZGlhbkFuZHJvaWRBcHBpdW1UcmFuc3BvcnRPcHRpb25zLFxuICBPYnNpZGlhbkNkcFRyYW5zcG9ydE9wdGlvbnMsXG4gIE9ic2lkaWFuVHJhbnNwb3J0T3B0aW9uc1xufSBmcm9tICcuL3RyYW5zcG9ydC1vcHRpb25zLmNqcyc7XG5leHBvcnQgdHlwZSB7XG4gIE9ic2lkaWFuVHJhbnNwb3J0LFxuICBUcmFuc3BvcnRFdmFsT3B0aW9uc1xufSBmcm9tICcuL3RyYW5zcG9ydC5janMnO1xuZXhwb3J0IHtcbiAgcmVnaXN0ZXJWYXVsdCxcbiAgdW5yZWdpc3RlclZhdWx0XG59IGZyb20gJy4vdmF1bHQtcmVnaXN0cnkuY2pzJztcbmV4cG9ydCB0eXBlIHsgT2JzaWRpYW5WZXJzaW9uTWF0cml4RW50cnkgfSBmcm9tICcuL3ZlcnNpb24tbWF0cml4LmNqcyc7XG5leHBvcnQgeyBERUZBVUxUX09CU0lESUFOX1ZFUlNJT05fU1BFQ1MgfSBmcm9tICcuL3ZlcnNpb24tbWF0cml4LmNqcyc7XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQVdBLHFDQUFvQztBQUVwQyx5Q0FBMEM7QUFLMUMsZ0NBS087QUFLUCw0QkFBNkI7QUFDN0Isd0JBQTBCO0FBSzFCLDhCQUdPO0FBS1AsaUNBQXVDO0FBRXZDLDZCQUFrQztBQU1sQyxvQ0FBNkM7QUFXN0MsOEJBQStCO0FBTS9CLDRCQUdPO0FBRVAsa0RBQWtEO0FBTWxELHFDQUE4QztBQUU5QywwQkFBb0M7QUFNcEMsK0JBQW1DO0FBQ25DLDhCQUdPO0FBRVAsOEJBQStCO0FBQy9CLGlEQUFnRDtBQUVoRCxnQ0FBeUM7QUFFekMsd0NBQXdDO0FBS3hDLDZCQUErQjtBQUsvQiw4QkFBZ0M7QUFNaEMsbUNBQW9DO0FBQ3BDLCtCQUEyQztBQVUzQyw0QkFHTztBQUVQLDRCQUErQzsiLAogICJuYW1lcyI6IFtdCn0K
|
package/dist/lib/cjs/index.d.cts
CHANGED
|
@@ -22,6 +22,8 @@ export type { ElectronCompatibility, ElectronCompatibilityTier, ResolveElectronC
|
|
|
22
22
|
export { resolveElectronCompatibility } from './electron-compatibility.cjs';
|
|
23
23
|
export type { EvalInObsidianParams, HoverElementParams, Lib, MoveMouseParams, PressKeyParams, TypeIntoEditorParams, UnhoverElementParams, WaitUntilParams } from './eval-in-obsidian.cjs';
|
|
24
24
|
export { evalInObsidian } from './eval-in-obsidian.cjs';
|
|
25
|
+
export type { ComputeFitToCanvasParams, FitScreenshotToCanvasOptions, FitToCanvasGeometry } from './fit-screenshot.cjs';
|
|
26
|
+
export { computeFitToCanvas, fitScreenshotToCanvas } from './fit-screenshot.cjs';
|
|
25
27
|
export type { IncompatibleInstallerVersionErrorConstructorParams } from './incompatible-installer-version-error.cjs';
|
|
26
28
|
export { IncompatibleInstallerVersionError } from './incompatible-installer-version-error.cjs';
|
|
27
29
|
export type { InstallerCompatibility, InstallerCompatibilityTier, ResolveInstallerCompatibilityParams } from './installer-compatibility.cjs';
|
package/dist/lib/cjs/library.cjs
CHANGED
|
@@ -21,7 +21,7 @@ __export(library_exports, {
|
|
|
21
21
|
LIBRARY_VERSION: () => LIBRARY_VERSION
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(library_exports);
|
|
24
|
-
const LIBRARY_VERSION = false ? "dev" : "10.
|
|
24
|
+
const LIBRARY_VERSION = false ? "dev" : "10.1.0";
|
|
25
25
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
26
|
0 && (module.exports = {
|
|
27
27
|
LIBRARY_VERSION
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
*
|
|
4
|
+
* Fits a screenshot onto a canvas of a different aspect ratio without cropping
|
|
5
|
+
* it or distorting it, filling the leftover margins with a blurred, enlarged
|
|
6
|
+
* copy of the same image (the "pillarbox" treatment used by store listings).
|
|
7
|
+
*
|
|
8
|
+
* The motivating case is a mobile store screenshot. The Android emulator's
|
|
9
|
+
* framebuffer is whatever the AVD's screen is — a Pixel 10 Pro XL is 1344x2992,
|
|
10
|
+
* roughly 9:20 — while the community store asks for 900x1600 (9:16). Cropping
|
|
11
|
+
* to 9:16 throws away a fifth of the frame, and stretching distorts the UI, so
|
|
12
|
+
* the image is scaled to fit the HEIGHT and the two side margins are filled.
|
|
13
|
+
*
|
|
14
|
+
* The geometry is a pure function so it can be unit-tested; the pixel work needs
|
|
15
|
+
* `sharp`, which is an OPTIONAL peer dependency — declared rather than bundled
|
|
16
|
+
* because only screenshot capture needs it, and it ships platform-specific
|
|
17
|
+
* native binaries that every other consumer would pay for.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Parameters for {@link computeFitToCanvas}.
|
|
21
|
+
*/
|
|
22
|
+
export interface ComputeFitToCanvasParams {
|
|
23
|
+
/**
|
|
24
|
+
* Height of the target canvas, in pixels.
|
|
25
|
+
*/
|
|
26
|
+
readonly canvasHeightInPixels: number;
|
|
27
|
+
/**
|
|
28
|
+
* Width of the target canvas, in pixels.
|
|
29
|
+
*/
|
|
30
|
+
readonly canvasWidthInPixels: number;
|
|
31
|
+
/**
|
|
32
|
+
* Height of the source image, in pixels.
|
|
33
|
+
*/
|
|
34
|
+
readonly sourceHeightInPixels: number;
|
|
35
|
+
/**
|
|
36
|
+
* Width of the source image, in pixels.
|
|
37
|
+
*/
|
|
38
|
+
readonly sourceWidthInPixels: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Options for {@link fitScreenshotToCanvas}.
|
|
42
|
+
*/
|
|
43
|
+
export interface FitScreenshotToCanvasOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Gaussian blur strength applied to the margin fill.
|
|
46
|
+
*
|
|
47
|
+
* @default `24`
|
|
48
|
+
*/
|
|
49
|
+
readonly blurSigma?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Height of the target canvas, in pixels.
|
|
52
|
+
*/
|
|
53
|
+
readonly canvasHeightInPixels: number;
|
|
54
|
+
/**
|
|
55
|
+
* Width of the target canvas, in pixels.
|
|
56
|
+
*/
|
|
57
|
+
readonly canvasWidthInPixels: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Where the scaled source image sits on the canvas.
|
|
61
|
+
*/
|
|
62
|
+
export interface FitToCanvasGeometry {
|
|
63
|
+
/**
|
|
64
|
+
* Width of each side margin, in pixels. Both sides are equal by construction.
|
|
65
|
+
*/
|
|
66
|
+
readonly marginInPixels: number;
|
|
67
|
+
/**
|
|
68
|
+
* Left offset of the scaled image on the canvas, in pixels.
|
|
69
|
+
*/
|
|
70
|
+
readonly offsetXInPixels: number;
|
|
71
|
+
/**
|
|
72
|
+
* Top offset of the scaled image on the canvas, in pixels.
|
|
73
|
+
*/
|
|
74
|
+
readonly offsetYInPixels: number;
|
|
75
|
+
/**
|
|
76
|
+
* Height the source is scaled to, in pixels.
|
|
77
|
+
*/
|
|
78
|
+
readonly scaledHeightInPixels: number;
|
|
79
|
+
/**
|
|
80
|
+
* Width the source is scaled to, in pixels.
|
|
81
|
+
*/
|
|
82
|
+
readonly scaledWidthInPixels: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Computes how a source image is scaled and placed to fill a canvas's height,
|
|
86
|
+
* with equal margins on the left and right.
|
|
87
|
+
*
|
|
88
|
+
* The scaled width is rounded to the nearest integer that leaves an EVEN
|
|
89
|
+
* remainder, so the two margins are exactly equal — an asymmetric pillarbox is
|
|
90
|
+
* visible at a glance and looks like a mistake. Where both neighbors qualify,
|
|
91
|
+
* the one closer to the true scaled width wins, so the aspect error stays below
|
|
92
|
+
* one part in a thousand.
|
|
93
|
+
*
|
|
94
|
+
* Worked example, the mobile store case: a 1344x2992 frame onto a 900x1600
|
|
95
|
+
* canvas scales by `1600/2992` to 718.72 wide. 719 would leave a 181px
|
|
96
|
+
* remainder, which cannot split evenly, so 718 is chosen (margin 91) over 720
|
|
97
|
+
* (margin 90) because 718 is nearer 718.72.
|
|
98
|
+
*
|
|
99
|
+
* @param params - The source and canvas dimensions.
|
|
100
|
+
* @returns The scaled size, the offsets, and the side margin.
|
|
101
|
+
* @throws Error if any dimension is not a positive number.
|
|
102
|
+
*/
|
|
103
|
+
export declare function computeFitToCanvas(params: ComputeFitToCanvasParams): FitToCanvasGeometry;
|
|
104
|
+
/**
|
|
105
|
+
* Scales a screenshot to fill a canvas's height and fills the side margins with
|
|
106
|
+
* a blurred, enlarged copy of the same image.
|
|
107
|
+
*
|
|
108
|
+
* Nothing is cropped and nothing is stretched: the visible screenshot keeps its
|
|
109
|
+
* aspect ratio to within a rounding pixel, and the margins are made of the
|
|
110
|
+
* image itself rather than a flat color, so the result reads as one frame.
|
|
111
|
+
*
|
|
112
|
+
* @param bytes - The source PNG.
|
|
113
|
+
* @param options - The target canvas size and blur strength.
|
|
114
|
+
* @returns A {@link Promise} that resolves to the composed PNG, exactly the canvas size.
|
|
115
|
+
* @throws Error if `sharp` is not installed, or the source dimensions cannot be read.
|
|
116
|
+
*/
|
|
117
|
+
export declare function fitScreenshotToCanvas(bytes: Uint8Array, options: FitScreenshotToCanvasOptions): Promise<Uint8Array>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const DEFAULT_BLUR_SIGMA = 24;
|
|
2
|
+
const MARGIN_SIDES = 2;
|
|
3
|
+
function computeFitToCanvas(params) {
|
|
4
|
+
const {
|
|
5
|
+
canvasHeightInPixels,
|
|
6
|
+
canvasWidthInPixels,
|
|
7
|
+
sourceHeightInPixels,
|
|
8
|
+
sourceWidthInPixels
|
|
9
|
+
} = params;
|
|
10
|
+
const namedDimensions = [
|
|
11
|
+
["canvasHeightInPixels", canvasHeightInPixels],
|
|
12
|
+
["canvasWidthInPixels", canvasWidthInPixels],
|
|
13
|
+
["sourceHeightInPixels", sourceHeightInPixels],
|
|
14
|
+
["sourceWidthInPixels", sourceWidthInPixels]
|
|
15
|
+
];
|
|
16
|
+
for (const [name, value] of namedDimensions) {
|
|
17
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
18
|
+
throw new Error(`computeFitToCanvas: ${name} must be a positive number, got ${String(value)}.`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const scaledHeightInPixels = canvasHeightInPixels;
|
|
22
|
+
const exactScaledWidth = sourceWidthInPixels * (canvasHeightInPixels / sourceHeightInPixels);
|
|
23
|
+
const scaledWidthInPixels = roundToMatchingParity(exactScaledWidth, canvasWidthInPixels);
|
|
24
|
+
if (scaledWidthInPixels > canvasWidthInPixels) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`computeFitToCanvas: the source is wider than the canvas once scaled to its height (${String(scaledWidthInPixels)} > ${String(canvasWidthInPixels)}); this fits by height and cannot letterbox.`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const marginInPixels = (canvasWidthInPixels - scaledWidthInPixels) / MARGIN_SIDES;
|
|
30
|
+
return {
|
|
31
|
+
marginInPixels,
|
|
32
|
+
offsetXInPixels: marginInPixels,
|
|
33
|
+
offsetYInPixels: 0,
|
|
34
|
+
scaledHeightInPixels,
|
|
35
|
+
scaledWidthInPixels
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function fitScreenshotToCanvas(bytes, options) {
|
|
39
|
+
const {
|
|
40
|
+
blurSigma = DEFAULT_BLUR_SIGMA,
|
|
41
|
+
canvasHeightInPixels,
|
|
42
|
+
canvasWidthInPixels
|
|
43
|
+
} = options;
|
|
44
|
+
const sharp = await importSharp();
|
|
45
|
+
const metadata = await sharp(bytes).metadata();
|
|
46
|
+
const sourceWidthInPixels = metadata.width;
|
|
47
|
+
const sourceHeightInPixels = metadata.height;
|
|
48
|
+
if (sourceWidthInPixels === void 0 || sourceHeightInPixels === void 0) {
|
|
49
|
+
throw new Error("fitScreenshotToCanvas: could not read the source image dimensions.");
|
|
50
|
+
}
|
|
51
|
+
const geometry = computeFitToCanvas({
|
|
52
|
+
canvasHeightInPixels,
|
|
53
|
+
canvasWidthInPixels,
|
|
54
|
+
sourceHeightInPixels,
|
|
55
|
+
sourceWidthInPixels
|
|
56
|
+
});
|
|
57
|
+
const background = await sharp(bytes).resize(canvasWidthInPixels, canvasHeightInPixels, { fit: "cover" }).blur(blurSigma).toBuffer();
|
|
58
|
+
const foreground = await sharp(bytes).resize(geometry.scaledWidthInPixels, geometry.scaledHeightInPixels, { fit: "fill" }).toBuffer();
|
|
59
|
+
const composed = await sharp(background).composite([{
|
|
60
|
+
input: foreground,
|
|
61
|
+
left: geometry.offsetXInPixels,
|
|
62
|
+
top: geometry.offsetYInPixels
|
|
63
|
+
}]).png().toBuffer();
|
|
64
|
+
return new Uint8Array(composed);
|
|
65
|
+
}
|
|
66
|
+
async function importSharp() {
|
|
67
|
+
try {
|
|
68
|
+
const sharpModule = await import("sharp");
|
|
69
|
+
const factory = sharpModule.default;
|
|
70
|
+
return factory;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
'fitScreenshotToCanvas needs the optional peer dependency "sharp". Install it in the consuming project (npm i -D sharp).',
|
|
74
|
+
{ cause: error }
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function roundToMatchingParity(value, target) {
|
|
79
|
+
const rounded = Math.round(value);
|
|
80
|
+
if ((target - rounded) % MARGIN_SIDES === 0) {
|
|
81
|
+
return rounded;
|
|
82
|
+
}
|
|
83
|
+
return value >= rounded ? rounded + 1 : rounded - 1;
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
computeFitToCanvas,
|
|
87
|
+
fitScreenshotToCanvas
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2ZpdC1zY3JlZW5zaG90LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogRml0cyBhIHNjcmVlbnNob3Qgb250byBhIGNhbnZhcyBvZiBhIGRpZmZlcmVudCBhc3BlY3QgcmF0aW8gd2l0aG91dCBjcm9wcGluZ1xuICogaXQgb3IgZGlzdG9ydGluZyBpdCwgZmlsbGluZyB0aGUgbGVmdG92ZXIgbWFyZ2lucyB3aXRoIGEgYmx1cnJlZCwgZW5sYXJnZWRcbiAqIGNvcHkgb2YgdGhlIHNhbWUgaW1hZ2UgKHRoZSBcInBpbGxhcmJveFwiIHRyZWF0bWVudCB1c2VkIGJ5IHN0b3JlIGxpc3RpbmdzKS5cbiAqXG4gKiBUaGUgbW90aXZhdGluZyBjYXNlIGlzIGEgbW9iaWxlIHN0b3JlIHNjcmVlbnNob3QuIFRoZSBBbmRyb2lkIGVtdWxhdG9yJ3NcbiAqIGZyYW1lYnVmZmVyIGlzIHdoYXRldmVyIHRoZSBBVkQncyBzY3JlZW4gaXMgXHUyMDE0IGEgUGl4ZWwgMTAgUHJvIFhMIGlzIDEzNDR4Mjk5MixcbiAqIHJvdWdobHkgOToyMCBcdTIwMTQgd2hpbGUgdGhlIGNvbW11bml0eSBzdG9yZSBhc2tzIGZvciA5MDB4MTYwMCAoOToxNikuIENyb3BwaW5nXG4gKiB0byA5OjE2IHRocm93cyBhd2F5IGEgZmlmdGggb2YgdGhlIGZyYW1lLCBhbmQgc3RyZXRjaGluZyBkaXN0b3J0cyB0aGUgVUksIHNvXG4gKiB0aGUgaW1hZ2UgaXMgc2NhbGVkIHRvIGZpdCB0aGUgSEVJR0hUIGFuZCB0aGUgdHdvIHNpZGUgbWFyZ2lucyBhcmUgZmlsbGVkLlxuICpcbiAqIFRoZSBnZW9tZXRyeSBpcyBhIHB1cmUgZnVuY3Rpb24gc28gaXQgY2FuIGJlIHVuaXQtdGVzdGVkOyB0aGUgcGl4ZWwgd29yayBuZWVkc1xuICogYHNoYXJwYCwgd2hpY2ggaXMgYW4gT1BUSU9OQUwgcGVlciBkZXBlbmRlbmN5IFx1MjAxNCBkZWNsYXJlZCByYXRoZXIgdGhhbiBidW5kbGVkXG4gKiBiZWNhdXNlIG9ubHkgc2NyZWVuc2hvdCBjYXB0dXJlIG5lZWRzIGl0LCBhbmQgaXQgc2hpcHMgcGxhdGZvcm0tc3BlY2lmaWNcbiAqIG5hdGl2ZSBiaW5hcmllcyB0aGF0IGV2ZXJ5IG90aGVyIGNvbnN1bWVyIHdvdWxkIHBheSBmb3IuXG4gKi9cblxuLyoqXG4gKiBQYXJhbWV0ZXJzIGZvciB7QGxpbmsgY29tcHV0ZUZpdFRvQ2FudmFzfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb21wdXRlRml0VG9DYW52YXNQYXJhbXMge1xuICAvKipcbiAgICogSGVpZ2h0IG9mIHRoZSB0YXJnZXQgY2FudmFzLCBpbiBwaXhlbHMuXG4gICAqL1xuICByZWFkb25seSBjYW52YXNIZWlnaHRJblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBXaWR0aCBvZiB0aGUgdGFyZ2V0IGNhbnZhcywgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgY2FudmFzV2lkdGhJblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBIZWlnaHQgb2YgdGhlIHNvdXJjZSBpbWFnZSwgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgc291cmNlSGVpZ2h0SW5QaXhlbHM6IG51bWJlcjtcblxuICAvKipcbiAgICogV2lkdGggb2YgdGhlIHNvdXJjZSBpbWFnZSwgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgc291cmNlV2lkdGhJblBpeGVsczogbnVtYmVyO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGluayBmaXRTY3JlZW5zaG90VG9DYW52YXN9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZpdFNjcmVlbnNob3RUb0NhbnZhc09wdGlvbnMge1xuICAvKipcbiAgICogR2F1c3NpYW4gYmx1ciBzdHJlbmd0aCBhcHBsaWVkIHRvIHRoZSBtYXJnaW4gZmlsbC5cbiAgICpcbiAgICogQGRlZmF1bHQgYDI0YFxuICAgKi9cbiAgcmVhZG9ubHkgYmx1clNpZ21hPzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBIZWlnaHQgb2YgdGhlIHRhcmdldCBjYW52YXMsIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IGNhbnZhc0hlaWdodEluUGl4ZWxzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFdpZHRoIG9mIHRoZSB0YXJnZXQgY2FudmFzLCBpbiBwaXhlbHMuXG4gICAqL1xuICByZWFkb25seSBjYW52YXNXaWR0aEluUGl4ZWxzOiBudW1iZXI7XG59XG5cbi8qKlxuICogV2hlcmUgdGhlIHNjYWxlZCBzb3VyY2UgaW1hZ2Ugc2l0cyBvbiB0aGUgY2FudmFzLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZpdFRvQ2FudmFzR2VvbWV0cnkge1xuICAvKipcbiAgICogV2lkdGggb2YgZWFjaCBzaWRlIG1hcmdpbiwgaW4gcGl4ZWxzLiBCb3RoIHNpZGVzIGFyZSBlcXVhbCBieSBjb25zdHJ1Y3Rpb24uXG4gICAqL1xuICByZWFkb25seSBtYXJnaW5JblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBMZWZ0IG9mZnNldCBvZiB0aGUgc2NhbGVkIGltYWdlIG9uIHRoZSBjYW52YXMsIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IG9mZnNldFhJblBpeGVsczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBUb3Agb2Zmc2V0IG9mIHRoZSBzY2FsZWQgaW1hZ2Ugb24gdGhlIGNhbnZhcywgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgb2Zmc2V0WUluUGl4ZWxzOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEhlaWdodCB0aGUgc291cmNlIGlzIHNjYWxlZCB0bywgaW4gcGl4ZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgc2NhbGVkSGVpZ2h0SW5QaXhlbHM6IG51bWJlcjtcblxuICAvKipcbiAgICogV2lkdGggdGhlIHNvdXJjZSBpcyBzY2FsZWQgdG8sIGluIHBpeGVscy5cbiAgICovXG4gIHJlYWRvbmx5IHNjYWxlZFdpZHRoSW5QaXhlbHM6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBBIGxheWVyIHBhc3NlZCB0byBgc2hhcnBgJ3MgYGNvbXBvc2l0ZWAuXG4gKi9cbmludGVyZmFjZSBTaGFycENvbXBvc2l0ZUxheWVyIHtcbiAgcmVhZG9ubHkgaW5wdXQ6IEJ1ZmZlcjtcbiAgcmVhZG9ubHkgbGVmdDogbnVtYmVyO1xuICByZWFkb25seSB0b3A6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBUaGUgYHNoYXJwYCBlbnRyeSBwb2ludCB0aGlzIG1vZHVsZSB1c2VzLCBkZXNjcmliZWQgc3RydWN0dXJhbGx5IHNvIHRoZSBtb2R1bGVcbiAqIHR5cGUtY2hlY2tzIGFnYWluc3QgdGhlIG9wdGlvbmFsIHBlZXIgcmF0aGVyIHRoYW4gZGVwZW5kaW5nIG9uIGl0cyB0eXBlcy5cbiAqL1xudHlwZSBTaGFycEZhY3RvcnkgPSAoaW5wdXQ6IFVpbnQ4QXJyYXkpID0+IFNoYXJwSW5zdGFuY2U7XG5cbi8qKlxuICogT25lIGBzaGFycGAgcGlwZWxpbmUuXG4gKi9cbmludGVyZmFjZSBTaGFycEluc3RhbmNlIHtcbiAgYmx1cih0aGlzOiB2b2lkLCBzaWdtYTogbnVtYmVyKTogU2hhcnBJbnN0YW5jZTtcbiAgY29tcG9zaXRlKHRoaXM6IHZvaWQsIGxheWVyczogU2hhcnBDb21wb3NpdGVMYXllcltdKTogU2hhcnBJbnN0YW5jZTtcbiAgbWV0YWRhdGEodGhpczogdm9pZCk6IFByb21pc2U8U2hhcnBNZXRhZGF0YT47XG4gIHBuZyh0aGlzOiB2b2lkKTogU2hhcnBJbnN0YW5jZTtcbiAgcmVzaXplKHRoaXM6IHZvaWQsIHdpZHRoOiBudW1iZXIsIGhlaWdodDogbnVtYmVyLCBvcHRpb25zPzogU2hhcnBSZXNpemVPcHRpb25zKTogU2hhcnBJbnN0YW5jZTtcbiAgdG9CdWZmZXIodGhpczogdm9pZCk6IFByb21pc2U8QnVmZmVyPjtcbn1cblxuLyoqXG4gKiBUaGUgc3Vic2V0IG9mIGBzaGFycGAncyBtZXRhZGF0YSB0aGlzIG1vZHVsZSByZWFkcy5cbiAqL1xuaW50ZXJmYWNlIFNoYXJwTWV0YWRhdGEge1xuICByZWFkb25seSBoZWlnaHQ/OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIHJlYWRvbmx5IHdpZHRoPzogbnVtYmVyIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFRoZSBzdWJzZXQgb2YgYHNoYXJwYCdzIHJlc2l6ZSBvcHRpb25zIHRoaXMgbW9kdWxlIHNldHMuXG4gKi9cbmludGVyZmFjZSBTaGFycFJlc2l6ZU9wdGlvbnMge1xuICByZWFkb25seSBmaXQ6ICdjb3ZlcicgfCAnZmlsbCc7XG59XG5cbi8qKlxuICogRGVmYXVsdCBHYXVzc2lhbiBibHVyIHN0cmVuZ3RoIGZvciB0aGUgbWFyZ2luIGZpbGw6IHNvZnQgZW5vdWdoIHRoYXQgbm9cbiAqIGRldGFpbCByZWFkcyBhcyBjb250ZW50LCBnZW50bGUgZW5vdWdoIHRvIGtlZXAgdGhlIGZyYW1lJ3MgY29sb3JzLlxuICovXG5jb25zdCBERUZBVUxUX0JMVVJfU0lHTUEgPSAyNDtcblxuLyoqXG4gKiBUaGUgbnVtYmVyIG9mIHNpZGUgbWFyZ2lucyB0aGUgbGVmdG92ZXIgd2lkdGggaXMgc3BsaXQgYmV0d2Vlbi5cbiAqL1xuY29uc3QgTUFSR0lOX1NJREVTID0gMjtcblxuLyoqXG4gKiBDb21wdXRlcyBob3cgYSBzb3VyY2UgaW1hZ2UgaXMgc2NhbGVkIGFuZCBwbGFjZWQgdG8gZmlsbCBhIGNhbnZhcydzIGhlaWdodCxcbiAqIHdpdGggZXF1YWwgbWFyZ2lucyBvbiB0aGUgbGVmdCBhbmQgcmlnaHQuXG4gKlxuICogVGhlIHNjYWxlZCB3aWR0aCBpcyByb3VuZGVkIHRvIHRoZSBuZWFyZXN0IGludGVnZXIgdGhhdCBsZWF2ZXMgYW4gRVZFTlxuICogcmVtYWluZGVyLCBzbyB0aGUgdHdvIG1hcmdpbnMgYXJlIGV4YWN0bHkgZXF1YWwgXHUyMDE0IGFuIGFzeW1tZXRyaWMgcGlsbGFyYm94IGlzXG4gKiB2aXNpYmxlIGF0IGEgZ2xhbmNlIGFuZCBsb29rcyBsaWtlIGEgbWlzdGFrZS4gV2hlcmUgYm90aCBuZWlnaGJvcnMgcXVhbGlmeSxcbiAqIHRoZSBvbmUgY2xvc2VyIHRvIHRoZSB0cnVlIHNjYWxlZCB3aWR0aCB3aW5zLCBzbyB0aGUgYXNwZWN0IGVycm9yIHN0YXlzIGJlbG93XG4gKiBvbmUgcGFydCBpbiBhIHRob3VzYW5kLlxuICpcbiAqIFdvcmtlZCBleGFtcGxlLCB0aGUgbW9iaWxlIHN0b3JlIGNhc2U6IGEgMTM0NHgyOTkyIGZyYW1lIG9udG8gYSA5MDB4MTYwMFxuICogY2FudmFzIHNjYWxlcyBieSBgMTYwMC8yOTkyYCB0byA3MTguNzIgd2lkZS4gNzE5IHdvdWxkIGxlYXZlIGEgMTgxcHhcbiAqIHJlbWFpbmRlciwgd2hpY2ggY2Fubm90IHNwbGl0IGV2ZW5seSwgc28gNzE4IGlzIGNob3NlbiAobWFyZ2luIDkxKSBvdmVyIDcyMFxuICogKG1hcmdpbiA5MCkgYmVjYXVzZSA3MTggaXMgbmVhcmVyIDcxOC43Mi5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIC0gVGhlIHNvdXJjZSBhbmQgY2FudmFzIGRpbWVuc2lvbnMuXG4gKiBAcmV0dXJucyBUaGUgc2NhbGVkIHNpemUsIHRoZSBvZmZzZXRzLCBhbmQgdGhlIHNpZGUgbWFyZ2luLlxuICogQHRocm93cyBFcnJvciBpZiBhbnkgZGltZW5zaW9uIGlzIG5vdCBhIHBvc2l0aXZlIG51bWJlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbXB1dGVGaXRUb0NhbnZhcyhwYXJhbXM6IENvbXB1dGVGaXRUb0NhbnZhc1BhcmFtcyk6IEZpdFRvQ2FudmFzR2VvbWV0cnkge1xuICBjb25zdCB7XG4gICAgY2FudmFzSGVpZ2h0SW5QaXhlbHMsXG4gICAgY2FudmFzV2lkdGhJblBpeGVscyxcbiAgICBzb3VyY2VIZWlnaHRJblBpeGVscyxcbiAgICBzb3VyY2VXaWR0aEluUGl4ZWxzXG4gIH0gPSBwYXJhbXM7XG5cbiAgY29uc3QgbmFtZWREaW1lbnNpb25zOiBbc3RyaW5nLCBudW1iZXJdW10gPSBbXG4gICAgWydjYW52YXNIZWlnaHRJblBpeGVscycsIGNhbnZhc0hlaWdodEluUGl4ZWxzXSxcbiAgICBbJ2NhbnZhc1dpZHRoSW5QaXhlbHMnLCBjYW52YXNXaWR0aEluUGl4ZWxzXSxcbiAgICBbJ3NvdXJjZUhlaWdodEluUGl4ZWxzJywgc291cmNlSGVpZ2h0SW5QaXhlbHNdLFxuICAgIFsnc291cmNlV2lkdGhJblBpeGVscycsIHNvdXJjZVdpZHRoSW5QaXhlbHNdXG4gIF07XG5cbiAgZm9yIChjb25zdCBbbmFtZSwgdmFsdWVdIG9mIG5hbWVkRGltZW5zaW9ucykge1xuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKHZhbHVlKSB8fCB2YWx1ZSA8PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGNvbXB1dGVGaXRUb0NhbnZhczogJHtuYW1lfSBtdXN0IGJlIGEgcG9zaXRpdmUgbnVtYmVyLCBnb3QgJHtTdHJpbmcodmFsdWUpfS5gKTtcbiAgICB9XG4gIH1cblxuICBjb25zdCBzY2FsZWRIZWlnaHRJblBpeGVscyA9IGNhbnZhc0hlaWdodEluUGl4ZWxzO1xuICBjb25zdCBleGFjdFNjYWxlZFdpZHRoID0gc291cmNlV2lkdGhJblBpeGVscyAqIChjYW52YXNIZWlnaHRJblBpeGVscyAvIHNvdXJjZUhlaWdodEluUGl4ZWxzKTtcbiAgY29uc3Qgc2NhbGVkV2lkdGhJblBpeGVscyA9IHJvdW5kVG9NYXRjaGluZ1Bhcml0eShleGFjdFNjYWxlZFdpZHRoLCBjYW52YXNXaWR0aEluUGl4ZWxzKTtcblxuICBpZiAoc2NhbGVkV2lkdGhJblBpeGVscyA+IGNhbnZhc1dpZHRoSW5QaXhlbHMpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnY29tcHV0ZUZpdFRvQ2FudmFzOiB0aGUgc291cmNlIGlzIHdpZGVyIHRoYW4gdGhlIGNhbnZhcyBvbmNlIHNjYWxlZCB0byBpdHMgaGVpZ2h0ICdcbiAgICAgICAgKyBgKCR7U3RyaW5nKHNjYWxlZFdpZHRoSW5QaXhlbHMpfSA+ICR7U3RyaW5nKGNhbnZhc1dpZHRoSW5QaXhlbHMpfSk7IHRoaXMgZml0cyBieSBoZWlnaHQgYW5kIGNhbm5vdCBsZXR0ZXJib3guYFxuICAgICk7XG4gIH1cblxuICBjb25zdCBtYXJnaW5JblBpeGVscyA9IChjYW52YXNXaWR0aEluUGl4ZWxzIC0gc2NhbGVkV2lkdGhJblBpeGVscykgLyBNQVJHSU5fU0lERVM7XG5cbiAgcmV0dXJuIHtcbiAgICBtYXJnaW5JblBpeGVscyxcbiAgICBvZmZzZXRYSW5QaXhlbHM6IG1hcmdpbkluUGl4ZWxzLFxuICAgIG9mZnNldFlJblBpeGVsczogMCxcbiAgICBzY2FsZWRIZWlnaHRJblBpeGVscyxcbiAgICBzY2FsZWRXaWR0aEluUGl4ZWxzXG4gIH07XG59XG5cbi8qKlxuICogU2NhbGVzIGEgc2NyZWVuc2hvdCB0byBmaWxsIGEgY2FudmFzJ3MgaGVpZ2h0IGFuZCBmaWxscyB0aGUgc2lkZSBtYXJnaW5zIHdpdGhcbiAqIGEgYmx1cnJlZCwgZW5sYXJnZWQgY29weSBvZiB0aGUgc2FtZSBpbWFnZS5cbiAqXG4gKiBOb3RoaW5nIGlzIGNyb3BwZWQgYW5kIG5vdGhpbmcgaXMgc3RyZXRjaGVkOiB0aGUgdmlzaWJsZSBzY3JlZW5zaG90IGtlZXBzIGl0c1xuICogYXNwZWN0IHJhdGlvIHRvIHdpdGhpbiBhIHJvdW5kaW5nIHBpeGVsLCBhbmQgdGhlIG1hcmdpbnMgYXJlIG1hZGUgb2YgdGhlXG4gKiBpbWFnZSBpdHNlbGYgcmF0aGVyIHRoYW4gYSBmbGF0IGNvbG9yLCBzbyB0aGUgcmVzdWx0IHJlYWRzIGFzIG9uZSBmcmFtZS5cbiAqXG4gKiBAcGFyYW0gYnl0ZXMgLSBUaGUgc291cmNlIFBORy5cbiAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIHRhcmdldCBjYW52YXMgc2l6ZSBhbmQgYmx1ciBzdHJlbmd0aC5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNvbXBvc2VkIFBORywgZXhhY3RseSB0aGUgY2FudmFzIHNpemUuXG4gKiBAdGhyb3dzIEVycm9yIGlmIGBzaGFycGAgaXMgbm90IGluc3RhbGxlZCwgb3IgdGhlIHNvdXJjZSBkaW1lbnNpb25zIGNhbm5vdCBiZSByZWFkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZml0U2NyZWVuc2hvdFRvQ2FudmFzKGJ5dGVzOiBVaW50OEFycmF5LCBvcHRpb25zOiBGaXRTY3JlZW5zaG90VG9DYW52YXNPcHRpb25zKTogUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gIGNvbnN0IHtcbiAgICBibHVyU2lnbWEgPSBERUZBVUxUX0JMVVJfU0lHTUEsXG4gICAgY2FudmFzSGVpZ2h0SW5QaXhlbHMsXG4gICAgY2FudmFzV2lkdGhJblBpeGVsc1xuICB9ID0gb3B0aW9ucztcblxuICBjb25zdCBzaGFycCA9IGF3YWl0IGltcG9ydFNoYXJwKCk7XG4gIGNvbnN0IG1ldGFkYXRhID0gYXdhaXQgc2hhcnAoYnl0ZXMpLm1ldGFkYXRhKCk7XG4gIGNvbnN0IHNvdXJjZVdpZHRoSW5QaXhlbHMgPSBtZXRhZGF0YS53aWR0aDtcbiAgY29uc3Qgc291cmNlSGVpZ2h0SW5QaXhlbHMgPSBtZXRhZGF0YS5oZWlnaHQ7XG5cbiAgLyogdjggaWdub3JlIG5leHQgMyAtLSBEZWZlbnNpdmU6IGBzaGFycGAgcmVqZWN0cyBhIG5vbi1pbWFnZSBiZWZvcmUgaXQgY2FuIHJlcG9ydCBtZXRhZGF0YSB3aXRob3V0IGRpbWVuc2lvbnMsIHNvIHRoaXMgYnJhbmNoIGlzIHVucmVhY2hhYmxlIGZyb20gYSB0ZXN0LiAqL1xuICBpZiAoc291cmNlV2lkdGhJblBpeGVscyA9PT0gdW5kZWZpbmVkIHx8IHNvdXJjZUhlaWdodEluUGl4ZWxzID09PSB1bmRlZmluZWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2ZpdFNjcmVlbnNob3RUb0NhbnZhczogY291bGQgbm90IHJlYWQgdGhlIHNvdXJjZSBpbWFnZSBkaW1lbnNpb25zLicpO1xuICB9XG5cbiAgY29uc3QgZ2VvbWV0cnkgPSBjb21wdXRlRml0VG9DYW52YXMoe1xuICAgIGNhbnZhc0hlaWdodEluUGl4ZWxzLFxuICAgIGNhbnZhc1dpZHRoSW5QaXhlbHMsXG4gICAgc291cmNlSGVpZ2h0SW5QaXhlbHMsXG4gICAgc291cmNlV2lkdGhJblBpeGVsc1xuICB9KTtcblxuICAvLyBUaGUgYmFja2dyb3VuZCBpcyB0aGUgc2FtZSBmcmFtZSBibG93biB1cCB0byBDT1ZFUiB0aGUgY2FudmFzIGFuZCBibHVycmVkLFxuICAvLyBTbyB0aGUgbWFyZ2lucyBjYXJyeSB0aGUgc2NyZWVuc2hvdCdzIG93biBjb2xvcnMgaW5zdGVhZCBvZiBhIGZsYXQgYmFyLlxuICBjb25zdCBiYWNrZ3JvdW5kID0gYXdhaXQgc2hhcnAoYnl0ZXMpXG4gICAgLnJlc2l6ZShjYW52YXNXaWR0aEluUGl4ZWxzLCBjYW52YXNIZWlnaHRJblBpeGVscywgeyBmaXQ6ICdjb3ZlcicgfSlcbiAgICAuYmx1cihibHVyU2lnbWEpXG4gICAgLnRvQnVmZmVyKCk7XG5cbiAgY29uc3QgZm9yZWdyb3VuZCA9IGF3YWl0IHNoYXJwKGJ5dGVzKVxuICAgIC5yZXNpemUoZ2VvbWV0cnkuc2NhbGVkV2lkdGhJblBpeGVscywgZ2VvbWV0cnkuc2NhbGVkSGVpZ2h0SW5QaXhlbHMsIHsgZml0OiAnZmlsbCcgfSlcbiAgICAudG9CdWZmZXIoKTtcblxuICBjb25zdCBjb21wb3NlZCA9IGF3YWl0IHNoYXJwKGJhY2tncm91bmQpXG4gICAgLmNvbXBvc2l0ZShbe1xuICAgICAgaW5wdXQ6IGZvcmVncm91bmQsXG4gICAgICBsZWZ0OiBnZW9tZXRyeS5vZmZzZXRYSW5QaXhlbHMsXG4gICAgICB0b3A6IGdlb21ldHJ5Lm9mZnNldFlJblBpeGVsc1xuICAgIH1dKVxuICAgIC5wbmcoKVxuICAgIC50b0J1ZmZlcigpO1xuXG4gIHJldHVybiBuZXcgVWludDhBcnJheShjb21wb3NlZCk7XG59XG5cbi8qKlxuICogTG9hZHMgYHNoYXJwYCBvbiBkZW1hbmQsIHNvIGltcG9ydGluZyB0aGlzIG1vZHVsZSBkb2VzIG5vdCByZXF1aXJlIGl0LlxuICpcbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGBzaGFycGAgZmFjdG9yeS5cbiAqIEB0aHJvd3MgRXJyb3IgbmFtaW5nIHRoZSBtaXNzaW5nIG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jeS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gaW1wb3J0U2hhcnAoKTogUHJvbWlzZTxTaGFycEZhY3Rvcnk+IHtcbiAgdHJ5IHtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tcmVzdHJpY3RlZC1zeW50YXggLS0gYHNoYXJwYCBpcyBhbiBPUFRJT05BTCBwZWVyLCBzbyBpdCBtdXN0IGJlIGxvYWRlZCBsYXppbHk6IGEgc3RhdGljIGltcG9ydCB3b3VsZCBkcmFnIGl0cyBuYXRpdmUgYmluYXJpZXMgaW50byBldmVyeSBjb25zdW1lciBvZiB0aGlzIHBhY2thZ2UncyBpbmRleC5cbiAgICBjb25zdCBzaGFycE1vZHVsZSA9IGF3YWl0IGltcG9ydCgnc2hhcnAnKTtcbiAgICBjb25zdCBmYWN0b3J5OiB1bmtub3duID0gc2hhcnBNb2R1bGUuZGVmYXVsdDtcbiAgICByZXR1cm4gZmFjdG9yeSBhcyBTaGFycEZhY3Rvcnk7XG4gIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgLyogdjggaWdub3JlIHN0YXJ0IC0tIFJlYWNoZWQgb25seSB3aGVuIHRoZSBvcHRpb25hbCBwZWVyIGlzIGFic2VudCwgd2hpY2ggaXQgbmV2ZXIgaXMgaW4gdGhpcyBwYWNrYWdlJ3Mgb3duIHRlc3QgcnVuLiAqL1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdmaXRTY3JlZW5zaG90VG9DYW52YXMgbmVlZHMgdGhlIG9wdGlvbmFsIHBlZXIgZGVwZW5kZW5jeSBcInNoYXJwXCIuICdcbiAgICAgICAgKyAnSW5zdGFsbCBpdCBpbiB0aGUgY29uc3VtaW5nIHByb2plY3QgKG5wbSBpIC1EIHNoYXJwKS4nLFxuICAgICAgeyBjYXVzZTogZXJyb3IgfVxuICAgICk7XG4gICAgLyogdjggaWdub3JlIHN0b3AgKi9cbiAgfVxufVxuXG4vKipcbiAqIFJvdW5kcyBhIHdpZHRoIHRvIHRoZSBuZWFyZXN0IGludGVnZXIgc2hhcmluZyBgdGFyZ2V0YCdzIHBhcml0eSwgc29cbiAqIGB0YXJnZXQgLSByZXN1bHRgIGlzIGV2ZW4gYW5kIHNwbGl0cyBpbnRvIHR3byBlcXVhbCBtYXJnaW5zLlxuICpcbiAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBleGFjdCBzY2FsZWQgd2lkdGguXG4gKiBAcGFyYW0gdGFyZ2V0IC0gVGhlIGNhbnZhcyB3aWR0aCB3aG9zZSBwYXJpdHkgbXVzdCBiZSBtYXRjaGVkLlxuICogQHJldHVybnMgVGhlIG5lYXJlc3QgaW50ZWdlciBvZiB0aGUgc2FtZSBwYXJpdHkgYXMgYHRhcmdldGAuXG4gKi9cbmZ1bmN0aW9uIHJvdW5kVG9NYXRjaGluZ1Bhcml0eSh2YWx1ZTogbnVtYmVyLCB0YXJnZXQ6IG51bWJlcik6IG51bWJlciB7XG4gIGNvbnN0IHJvdW5kZWQgPSBNYXRoLnJvdW5kKHZhbHVlKTtcbiAgaWYgKCh0YXJnZXQgLSByb3VuZGVkKSAlIE1BUkdJTl9TSURFUyA9PT0gMCkge1xuICAgIHJldHVybiByb3VuZGVkO1xuICB9XG5cbiAgLy8gYHJvdW5kZWRgIGxlYXZlcyBhbiBvZGQgcmVtYWluZGVyLCBzbyBzdGVwIHRvIHdoaWNoZXZlciBuZWlnaGJvciBpcyBjbG9zZXJcbiAgLy8gVG8gdGhlIHRydWUgdmFsdWU7IGJvdGggaGF2ZSB0aGUgcGFyaXR5IGByb3VuZGVkYCBsYWNrcy5cbiAgcmV0dXJuIHZhbHVlID49IHJvdW5kZWQgPyByb3VuZGVkICsgMSA6IHJvdW5kZWQgLSAxO1xufVxuIl0sCiAgIm1hcHBpbmdzIjogIkFBOElBLE1BQU0scUJBQXFCO0FBSzNCLE1BQU0sZUFBZTtBQXFCZCxTQUFTLG1CQUFtQixRQUF1RDtBQUN4RixRQUFNO0FBQUEsSUFDSjtBQUFBLElBQ0E7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVB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
|
package/dist/lib/esm/index.d.mts
CHANGED
|
@@ -22,6 +22,8 @@ export type { ElectronCompatibility, ElectronCompatibilityTier, ResolveElectronC
|
|
|
22
22
|
export { resolveElectronCompatibility } from './electron-compatibility.mjs';
|
|
23
23
|
export type { EvalInObsidianParams, HoverElementParams, Lib, MoveMouseParams, PressKeyParams, TypeIntoEditorParams, UnhoverElementParams, WaitUntilParams } from './eval-in-obsidian.mjs';
|
|
24
24
|
export { evalInObsidian } from './eval-in-obsidian.mjs';
|
|
25
|
+
export type { ComputeFitToCanvasParams, FitScreenshotToCanvasOptions, FitToCanvasGeometry } from './fit-screenshot.mjs';
|
|
26
|
+
export { computeFitToCanvas, fitScreenshotToCanvas } from './fit-screenshot.mjs';
|
|
25
27
|
export type { IncompatibleInstallerVersionErrorConstructorParams } from './incompatible-installer-version-error.mjs';
|
|
26
28
|
export { IncompatibleInstallerVersionError } from './incompatible-installer-version-error.mjs';
|
|
27
29
|
export type { InstallerCompatibility, InstallerCompatibilityTier, ResolveInstallerCompatibilityParams } from './installer-compatibility.mjs';
|
package/dist/lib/esm/index.mjs
CHANGED
|
@@ -16,6 +16,10 @@ import { buildDemoVaultPopulate } from "./demo-vault-populate.mjs";
|
|
|
16
16
|
import { readDemoVaultTree } from "./demo-vault-tree.mjs";
|
|
17
17
|
import { resolveElectronCompatibility } from "./electron-compatibility.mjs";
|
|
18
18
|
import { evalInObsidian } from "./eval-in-obsidian.mjs";
|
|
19
|
+
import {
|
|
20
|
+
computeFitToCanvas,
|
|
21
|
+
fitScreenshotToCanvas
|
|
22
|
+
} from "./fit-screenshot.mjs";
|
|
19
23
|
import { IncompatibleInstallerVersionError } from "./incompatible-installer-version-error.mjs";
|
|
20
24
|
import { resolveInstallerCompatibility } from "./installer-compatibility.mjs";
|
|
21
25
|
import { registerLibResolver } from "./lib-registry.mjs";
|
|
@@ -51,10 +55,12 @@ export {
|
|
|
51
55
|
buildDemoVaultPopulate,
|
|
52
56
|
buildDeviceMetricsOverride,
|
|
53
57
|
captureObsidianScreenshot,
|
|
58
|
+
computeFitToCanvas,
|
|
54
59
|
connectToCdp,
|
|
55
60
|
createTransportFromOptions,
|
|
56
61
|
decodeBase64Png,
|
|
57
62
|
evalInObsidian,
|
|
63
|
+
fitScreenshotToCanvas,
|
|
58
64
|
getVersionMetadata,
|
|
59
65
|
isPng,
|
|
60
66
|
pollInObsidian,
|
|
@@ -70,4 +76,4 @@ export {
|
|
|
70
76
|
setVaultPathResolver,
|
|
71
77
|
unregisterVault
|
|
72
78
|
};
|
|
73
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
79
|
+
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2luZGV4LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogQ29udGFpbnMgdGhlIGVudHJ5IHBvaW50IGZvciB0aGUgaW50ZWdyYXRpb24gdGVzdGluZyBtb2R1bGUuXG4gKi9cblxuZXhwb3J0IHR5cGUge1xuICBBc2FyRmFsbGJhY2ssXG4gIEFzYXJGYWxsYmFja1RpZXIsXG4gIFJlc29sdmVBc2FyRmFsbGJhY2tQYXJhbXNcbn0gZnJvbSAnLi9hc2FyLWZhbGxiYWNrLWRldGVjdGlvbi5tanMnO1xuZXhwb3J0IHsgcmVzb2x2ZUFzYXJGYWxsYmFjayB9IGZyb20gJy4vYXNhci1mYWxsYmFjay1kZXRlY3Rpb24ubWpzJztcbmV4cG9ydCB0eXBlIHsgQ2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdE9wdGlvbnMgfSBmcm9tICcuL2NhcHR1cmUtb2JzaWRpYW4tc2NyZWVuc2hvdC5tanMnO1xuZXhwb3J0IHsgY2FwdHVyZU9ic2lkaWFuU2NyZWVuc2hvdCB9IGZyb20gJy4vY2FwdHVyZS1vYnNpZGlhbi1zY3JlZW5zaG90Lm1qcyc7XG5leHBvcnQgdHlwZSB7XG4gIENhcHR1cmVTY3JlZW5zaG90UGFyYW1zLFxuICBQbmdEaW1lbnNpb25zXG59IGZyb20gJy4vY2FwdHVyZS1zY3JlZW5zaG90Lm1qcyc7XG5leHBvcnQge1xuICBidWlsZERldmljZU1ldHJpY3NPdmVycmlkZSxcbiAgZGVjb2RlQmFzZTY0UG5nLFxuICBpc1BuZyxcbiAgcmVhZFBuZ0RpbWVuc2lvbnNcbn0gZnJvbSAnLi9jYXB0dXJlLXNjcmVlbnNob3QubWpzJztcbmV4cG9ydCB0eXBlIHtcbiAgQ2RwQ29ubmVjdGlvbixcbiAgQ29ubmVjdFRvQ2RwT3B0aW9uc1xufSBmcm9tICcuL2Nvbm5lY3QtdG8tY2RwLm1qcyc7XG5leHBvcnQgeyBjb25uZWN0VG9DZHAgfSBmcm9tICcuL2Nvbm5lY3QtdG8tY2RwLm1qcyc7XG5leHBvcnQgeyBDb250ZXh0SWQgfSBmcm9tICcuL2NvbnRleHQtaWQubWpzJztcbmV4cG9ydCB0eXBlIHtcbiAgVHJhbnNwb3J0T3B0aW9uc1Jlc29sdmVyLFxuICBWYXVsdFBhdGhSZXNvbHZlclxufSBmcm9tICcuL2NvbnRleHQtcHJvdmlkZXIubWpzJztcbmV4cG9ydCB7XG4gIHNldFRyYW5zcG9ydE9wdGlvbnNSZXNvbHZlcixcbiAgc2V0VmF1bHRQYXRoUmVzb2x2ZXJcbn0gZnJvbSAnLi9jb250ZXh0LXByb3ZpZGVyLm1qcyc7XG5leHBvcnQgdHlwZSB7XG4gIEJ1aWxkRGVtb1ZhdWx0UG9wdWxhdGVQYXJhbXMsXG4gIEluamVjdFBsdWdpblBhcmFtc1xufSBmcm9tICcuL2RlbW8tdmF1bHQtcG9wdWxhdGUubWpzJztcbmV4cG9ydCB7IGJ1aWxkRGVtb1ZhdWx0UG9wdWxhdGUgfSBmcm9tICcuL2RlbW8tdmF1bHQtcG9wdWxhdGUubWpzJztcbmV4cG9ydCB0eXBlIHsgUmVhZERlbW9WYXVsdFRyZWVQYXJhbXMgfSBmcm9tICcuL2RlbW8tdmF1bHQtdHJlZS5tanMnO1xuZXhwb3J0IHsgcmVhZERlbW9WYXVsdFRyZWUgfSBmcm9tICcuL2RlbW8tdmF1bHQtdHJlZS5tanMnO1xuZXhwb3J0IHR5cGUge1xuICBFbGVjdHJvbkNvbXBhdGliaWxpdHksXG4gIEVsZWN0cm9uQ29tcGF0aWJpbGl0eVRpZXIsXG4gIFJlc29sdmVFbGVjdHJvbkNvbXBhdGliaWxpdHlQYXJhbXNcbn0gZnJvbSAnLi9lbGVjdHJvbi1jb21wYXRpYmlsaXR5Lm1qcyc7XG5leHBvcnQgeyByZXNvbHZlRWxlY3Ryb25Db21wYXRpYmlsaXR5IH0gZnJvbSAnLi9lbGVjdHJvbi1jb21wYXRpYmlsaXR5Lm1qcyc7XG5leHBvcnQgdHlwZSB7XG4gIEV2YWxJbk9ic2lkaWFuUGFyYW1zLFxuICBIb3ZlckVsZW1lbnRQYXJhbXMsXG4gIExpYixcbiAgTW92ZU1vdXNlUGFyYW1zLFxuICBQcmVzc0tleVBhcmFtcyxcbiAgVHlwZUludG9FZGl0b3JQYXJhbXMsXG4gIFVuaG92ZXJFbGVtZW50UGFyYW1zLFxuICBXYWl0VW50aWxQYXJhbXNcbn0gZnJvbSAnLi9ldmFsLWluLW9ic2lkaWFuLm1qcyc7XG5leHBvcnQgeyBldmFsSW5PYnNpZGlhbiB9IGZyb20gJy4vZXZhbC1pbi1vYnNpZGlhbi5tanMnO1xuZXhwb3J0IHR5cGUge1xuICBDb21wdXRlRml0VG9DYW52YXNQYXJhbXMsXG4gIEZpdFNjcmVlbnNob3RUb0NhbnZhc09wdGlvbnMsXG4gIEZpdFRvQ2FudmFzR2VvbWV0cnlcbn0gZnJvbSAnLi9maXQtc2NyZWVuc2hvdC5tanMnO1xuZXhwb3J0IHtcbiAgY29tcHV0ZUZpdFRvQ2FudmFzLFxuICBmaXRTY3JlZW5zaG90VG9DYW52YXNcbn0gZnJvbSAnLi9maXQtc2NyZWVuc2hvdC5tanMnO1xuZXhwb3J0IHR5cGUgeyBJbmNvbXBhdGlibGVJbnN0YWxsZXJWZXJzaW9uRXJyb3JDb25zdHJ1Y3RvclBhcmFtcyB9IGZyb20gJy4vaW5jb21wYXRpYmxlLWluc3RhbGxlci12ZXJzaW9uLWVycm9yLm1qcyc7XG5leHBvcnQgeyBJbmNvbXBhdGlibGVJbnN0YWxsZXJWZXJzaW9uRXJyb3IgfSBmcm9tICcuL2luY29tcGF0aWJsZS1pbnN0YWxsZXItdmVyc2lvbi1lcnJvci5tanMnO1xuZXhwb3J0IHR5cGUge1xuICBJbnN0YWxsZXJDb21wYXRpYmlsaXR5LFxuICBJbnN0YWxsZXJDb21wYXRpYmlsaXR5VGllcixcbiAgUmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHlQYXJhbXNcbn0gZnJvbSAnLi9pbnN0YWxsZXItY29tcGF0aWJpbGl0eS5tanMnO1xuZXhwb3J0IHsgcmVzb2x2ZUluc3RhbGxlckNvbXBhdGliaWxpdHkgfSBmcm9tICcuL2luc3RhbGxlci1jb21wYXRpYmlsaXR5Lm1qcyc7XG5leHBvcnQgdHlwZSB7IExpYlJlc29sdmVyIH0gZnJvbSAnLi9saWItcmVnaXN0cnkubWpzJztcbmV4cG9ydCB7IHJlZ2lzdGVyTGliUmVzb2x2ZXIgfSBmcm9tICcuL2xpYi1yZWdpc3RyeS5tanMnO1xuZXhwb3J0IHR5cGUge1xuICBPYnNpZGlhblJ1bnRpbWVWZXJzaW9ucyxcbiAgT2JzaWRpYW5WZXJzaW9uRG93bmxvYWRzLFxuICBPYnNpZGlhblZlcnNpb25NZXRhZGF0YVxufSBmcm9tICcuL29ic2lkaWFuLW1ldGFkYXRhLm1qcyc7XG5leHBvcnQgeyBnZXRWZXJzaW9uTWV0YWRhdGEgfSBmcm9tICcuL29ic2lkaWFuLW1ldGFkYXRhLm1qcyc7XG5leHBvcnQge1xuICBDQVRBTFlTVF9MQVRFU1QsXG4gIFBVQkxJQ19MQVRFU1Rcbn0gZnJvbSAnLi9vYnNpZGlhbi12ZXJzaW9uLm1qcyc7XG5leHBvcnQgdHlwZSB7IFBvbGxJbk9ic2lkaWFuUGFyYW1zIH0gZnJvbSAnLi9wb2xsLWluLW9ic2lkaWFuLm1qcyc7XG5leHBvcnQgeyBwb2xsSW5PYnNpZGlhbiB9IGZyb20gJy4vcG9sbC1pbi1vYnNpZGlhbi5tanMnO1xuZXhwb3J0IHsgUmVuZGVyZXJGYWlsZWRUb0luaXRpYWxpemVFcnJvciB9IGZyb20gJy4vcmVuZGVyZXItZmFpbGVkLXRvLWluaXRpYWxpemUtZXJyb3IubWpzJztcbmV4cG9ydCB0eXBlIHsgUnVuT2JzaWRpYW5WZXJzaW9uTWF0cml4UGFyYW1zIH0gZnJvbSAnLi9ydW4tdmVyc2lvbi1tYXRyaXgubWpzJztcbmV4cG9ydCB7IHJ1bk9ic2lkaWFuVmVyc2lvbk1hdHJpeCB9IGZyb20gJy4vcnVuLXZlcnNpb24tbWF0cml4Lm1qcyc7XG5leHBvcnQgdHlwZSB7IFNpbGVudEFzYXJGYWxsYmFja0Vycm9yQ29uc3RydWN0b3JQYXJhbXMgfSBmcm9tICcuL3NpbGVudC1hc2FyLWZhbGxiYWNrLWVycm9yLm1qcyc7XG5leHBvcnQgeyBTaWxlbnRBc2FyRmFsbGJhY2tFcnJvciB9IGZyb20gJy4vc2lsZW50LWFzYXItZmFsbGJhY2stZXJyb3IubWpzJztcbmV4cG9ydCB0eXBlIHtcbiAgUG9wdWxhdGVGaWxlQ29udGVudCxcbiAgUG9wdWxhdGVGaWxlc1BhcmFtc1xufSBmcm9tICcuL3RlbXBvcmFyeS12YXVsdC5tanMnO1xuZXhwb3J0IHsgVGVtcG9yYXJ5VmF1bHQgfSBmcm9tICcuL3RlbXBvcmFyeS12YXVsdC5tanMnO1xuZXhwb3J0IHR5cGUge1xuICBBcHBpdW1TZXNzaW9uSW5mbyxcbiAgQXBwaXVtVHJhbnNwb3J0Q29uZmlnXG59IGZyb20gJy4vdHJhbnNwb3J0LWFwcGl1bS5tanMnO1xuZXhwb3J0IHsgQXBwaXVtVHJhbnNwb3J0IH0gZnJvbSAnLi90cmFuc3BvcnQtYXBwaXVtLm1qcyc7XG5leHBvcnQgdHlwZSB7XG4gIERlc2t0b3BDZHBUcmFuc3BvcnRDb25maWcsXG4gIE93bmVkSW5zdGFuY2VBc2FyLFxuICBPd25lZEluc3RhbmNlQ29uZmlnXG59IGZyb20gJy4vdHJhbnNwb3J0LWRlc2t0b3AtY2RwLm1qcyc7XG5leHBvcnQgeyBEZXNrdG9wQ2RwVHJhbnNwb3J0IH0gZnJvbSAnLi90cmFuc3BvcnQtZGVza3RvcC1jZHAubWpzJztcbmV4cG9ydCB7IGNyZWF0ZVRyYW5zcG9ydEZyb21PcHRpb25zIH0gZnJvbSAnLi90cmFuc3BvcnQtZmFjdG9yeS5tanMnO1xuZXhwb3J0IHR5cGUge1xuICBPYnNpZGlhbkFuZHJvaWRBcHBpdW1UcmFuc3BvcnRPcHRpb25zLFxuICBPYnNpZGlhbkNkcFRyYW5zcG9ydE9wdGlvbnMsXG4gIE9ic2lkaWFuVHJhbnNwb3J0T3B0aW9uc1xufSBmcm9tICcuL3RyYW5zcG9ydC1vcHRpb25zLm1qcyc7XG5leHBvcnQgdHlwZSB7XG4gIE9ic2lkaWFuVHJhbnNwb3J0LFxuICBUcmFuc3BvcnRFdmFsT3B0aW9uc1xufSBmcm9tICcuL3RyYW5zcG9ydC5tanMnO1xuZXhwb3J0IHtcbiAgcmVnaXN0ZXJWYXVsdCxcbiAgdW5yZWdpc3RlclZhdWx0XG59IGZyb20gJy4vdmF1bHQtcmVnaXN0cnkubWpzJztcbmV4cG9ydCB0eXBlIHsgT2JzaWRpYW5WZXJzaW9uTWF0cml4RW50cnkgfSBmcm9tICcuL3ZlcnNpb24tbWF0cml4Lm1qcyc7XG5leHBvcnQgeyBERUZBVUxUX09CU0lESUFOX1ZFUlNJT05fU1BFQ1MgfSBmcm9tICcuL3ZlcnNpb24tbWF0cml4Lm1qcyc7XG4iXSwKICAibWFwcGluZ3MiOiAiQUFXQSxTQUFTLDJCQUEyQjtBQUVwQyxTQUFTLGlDQUFpQztBQUsxQztBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBS1AsU0FBUyxvQkFBb0I7QUFDN0IsU0FBUyxpQkFBaUI7QUFLMUI7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFLUCxTQUFTLDhCQUE4QjtBQUV2QyxTQUFTLHlCQUF5QjtBQU1sQyxTQUFTLG9DQUFvQztBQVc3QyxTQUFTLHNCQUFzQjtBQU0vQjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUVQLFNBQVMseUNBQXlDO0FBTWxELFNBQVMscUNBQXFDO0FBRTlDLFNBQVMsMkJBQTJCO0FBTXBDLFNBQVMsMEJBQTBCO0FBQ25DO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBRVAsU0FBUyxzQkFBc0I7QUFDL0IsU0FBUyx1Q0FBdUM7QUFFaEQsU0FBUyxnQ0FBZ0M7QUFFekMsU0FBUywrQkFBK0I7QUFLeEMsU0FBUyxzQkFBc0I7QUFLL0IsU0FBUyx1QkFBdUI7QUFNaEMsU0FBUywyQkFBMkI7QUFDcEMsU0FBUyxrQ0FBa0M7QUFVM0M7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFFUCxTQUFTLHNDQUFzQzsiLAogICJuYW1lcyI6IFtdCn0K
|
package/dist/lib/esm/library.mjs
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "obsidian-integration-testing",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.2.0",
|
|
4
4
|
"description": "Simplifies integration testing of Obsidian plugins.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"obsidian",
|
|
@@ -227,6 +227,7 @@
|
|
|
227
227
|
"obsidian": "^1.13.1",
|
|
228
228
|
"satori": "^0.29.0",
|
|
229
229
|
"semver": "^7.8.5",
|
|
230
|
+
"sharp": "^0.35.3",
|
|
230
231
|
"starlight-github-alerts": "^0.4.0",
|
|
231
232
|
"ts-jest": "^29.4.12",
|
|
232
233
|
"ts-morph": "^28.0.0",
|
|
@@ -241,6 +242,12 @@
|
|
|
241
242
|
},
|
|
242
243
|
"peerDependencies": {
|
|
243
244
|
"obsidian": "^1.12.3",
|
|
245
|
+
"sharp": "^0.35.3",
|
|
244
246
|
"type-fest": "^5.6.0"
|
|
247
|
+
},
|
|
248
|
+
"peerDependenciesMeta": {
|
|
249
|
+
"sharp": {
|
|
250
|
+
"optional": true
|
|
251
|
+
}
|
|
245
252
|
}
|
|
246
253
|
}
|
|
Binary file
|