pi-image-tools 1.3.1 → 1.4.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/CHANGELOG.md +135 -123
- package/README.md +10 -5
- package/package.json +13 -4
- package/src/config.ts +3 -0
- package/src/debug-logger.ts +4 -2
- package/src/image-preview.ts +25 -32
- package/src/image-transcode.ts +9 -1
- package/src/index.ts +23 -27
- package/src/inline-user-preview.ts +512 -523
- package/src/powershell.ts +82 -56
- package/src/preview-logging.ts +28 -0
- package/src/providers/command-runner.ts +19 -1
- package/src/providers/mac-osascript-pngf.ts +62 -101
- package/src/providers/mac-osascript-publicpng.ts +38 -77
- package/src/providers/mac-pngpaste.ts +30 -69
- package/src/providers/powershell-forms.ts +8 -16
- package/src/providers/provider-helpers.ts +196 -0
- package/src/providers/wl-paste.ts +46 -81
- package/src/providers/xclip.ts +51 -87
- package/src/recent-images.ts +54 -83
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { runPowerShellCommand, type PowerShellCommandResult, type RunPowerShellCommandOptions } from "../powershell.js";
|
|
2
2
|
import { MAX_BUFFER_BYTES, READ_TIMEOUT_MS } from "./command-runner.js";
|
|
3
|
+
import { mapProviderReadFallback, providerEmptyImage, providerImageResult } from "./provider-helpers.js";
|
|
3
4
|
import type { ClipboardImageProvider, ClipboardProviderContext, ClipboardReadResult } from "./types.js";
|
|
4
5
|
|
|
5
6
|
export type PowerShellRunner = (
|
|
@@ -62,34 +63,25 @@ export class PowerShellFormsProvider implements ClipboardImageProvider {
|
|
|
62
63
|
timeout: READ_TIMEOUT_MS,
|
|
63
64
|
});
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (!result.ok) {
|
|
70
|
-
return { available: true, image: null };
|
|
66
|
+
const fallback = mapProviderReadFallback(result, false);
|
|
67
|
+
if (fallback) {
|
|
68
|
+
return fallback;
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
const base64 = result.stdout.trim();
|
|
74
72
|
if (!base64) {
|
|
75
|
-
return
|
|
73
|
+
return providerEmptyImage();
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
try {
|
|
79
77
|
const bytes = Buffer.from(base64, "base64");
|
|
80
78
|
if (bytes.length === 0) {
|
|
81
|
-
return
|
|
79
|
+
return providerEmptyImage();
|
|
82
80
|
}
|
|
83
81
|
|
|
84
|
-
return
|
|
85
|
-
available: true,
|
|
86
|
-
image: {
|
|
87
|
-
bytes: new Uint8Array(bytes),
|
|
88
|
-
mimeType: "image/png",
|
|
89
|
-
},
|
|
90
|
-
};
|
|
82
|
+
return providerImageResult(new Uint8Array(bytes), "image/png");
|
|
91
83
|
} catch {
|
|
92
|
-
return
|
|
84
|
+
return providerEmptyImage();
|
|
93
85
|
}
|
|
94
86
|
}
|
|
95
87
|
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { buildNamespaceWrappedCommand, defaultCommandExists, type CommandExists } from "../shell-environment.js";
|
|
2
|
+
import {
|
|
3
|
+
defaultCommandRunner,
|
|
4
|
+
MAX_BUFFER_BYTES,
|
|
5
|
+
READ_TIMEOUT_MS,
|
|
6
|
+
type CommandResult,
|
|
7
|
+
type CommandRunner,
|
|
8
|
+
} from "./command-runner.js";
|
|
9
|
+
import type {
|
|
10
|
+
ClipboardImageProvider,
|
|
11
|
+
ClipboardProviderContext,
|
|
12
|
+
ClipboardReadResult,
|
|
13
|
+
ProviderCapabilities,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
// Re-export the symbols command-based providers reference in their read
|
|
17
|
+
// overrides and option types. Routing every concrete provider's import
|
|
18
|
+
// through this one module — the shared `CommandRunnerProviderOptions`
|
|
19
|
+
// interface, the `LIST_TYPES_TIMEOUT_MS` constant, and the result types —
|
|
20
|
+
// keeps their import blocks short and avoids duplicated multi-line import
|
|
21
|
+
// boilerplate across providers.
|
|
22
|
+
export type { CommandExists } from "../shell-environment.js";
|
|
23
|
+
export type { CommandResult, CommandRunner } from "./command-runner.js";
|
|
24
|
+
export { LIST_TYPES_TIMEOUT_MS } from "./command-runner.js";
|
|
25
|
+
export type { ClipboardProviderContext, ClipboardReadResult } from "./types.js";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Minimal read-result shape shared by command-based and PowerShell-based
|
|
29
|
+
* clipboard providers. Both `CommandResult` (Buffer stdout) and
|
|
30
|
+
* `PowerShellCommandResult` (string stdout) satisfy this structural contract.
|
|
31
|
+
*/
|
|
32
|
+
interface ProviderReadResult {
|
|
33
|
+
missingCommand: boolean;
|
|
34
|
+
ok: boolean;
|
|
35
|
+
stdout: { length: number };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Result returned when the provider's command is not installed. */
|
|
39
|
+
export function providerUnavailable(): { available: false; image: null } {
|
|
40
|
+
return { available: false, image: null };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Result returned when the clipboard is available but holds no image. */
|
|
44
|
+
export function providerEmptyImage(): { available: true; image: null } {
|
|
45
|
+
return { available: true, image: null };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Result returned when a provider successfully read an image. */
|
|
49
|
+
export function providerImageResult(bytes: Uint8Array, mimeType: string): ClipboardReadResult {
|
|
50
|
+
return { available: true, image: { bytes, mimeType } };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Shared `isAvailable` implementation for providers that delegate to an
|
|
55
|
+
* external command whose presence is verified via `commandExists`.
|
|
56
|
+
*/
|
|
57
|
+
export function createCommandAvailabilityChecker(
|
|
58
|
+
commandName: string,
|
|
59
|
+
commandExists: CommandExists = defaultCommandExists,
|
|
60
|
+
): (context: ClipboardProviderContext) => boolean {
|
|
61
|
+
return (context: ClipboardProviderContext): boolean => {
|
|
62
|
+
try {
|
|
63
|
+
return commandExists(commandName, context);
|
|
64
|
+
} catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Maps a command read result to the standard unavailable/empty sentinel.
|
|
72
|
+
* Returns `null` when the caller should continue processing the result.
|
|
73
|
+
*/
|
|
74
|
+
export function mapProviderReadFallback(
|
|
75
|
+
result: ProviderReadResult,
|
|
76
|
+
requireNonEmptyStdout = true,
|
|
77
|
+
): { available: false; image: null } | { available: true; image: null } | null {
|
|
78
|
+
if (result.missingCommand) {
|
|
79
|
+
return providerUnavailable();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const isEmpty = !result.ok || (requireNonEmptyStdout && result.stdout.length === 0);
|
|
83
|
+
return isEmpty ? providerEmptyImage() : null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Parses a command's stdout — a newline-separated list of MIME types as
|
|
88
|
+
* emitted by `wl-paste --list-types` / `xclip -t TARGETS -o` — into a
|
|
89
|
+
* trimmed, non-empty list. Shared by the Linux command-based providers so
|
|
90
|
+
* the parse chain is not duplicated per provider.
|
|
91
|
+
*/
|
|
92
|
+
export function parseMimeTypeList(stdout: Buffer): string[] {
|
|
93
|
+
return stdout
|
|
94
|
+
.toString("utf8")
|
|
95
|
+
.split(/\r?\n/)
|
|
96
|
+
.map((mimeType) => mimeType.trim())
|
|
97
|
+
.filter((mimeType) => mimeType.length > 0);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Options shared by namespace-wrapped (macOS) command providers. */
|
|
101
|
+
export interface NamespacedCommandProviderOptions {
|
|
102
|
+
priority?: number;
|
|
103
|
+
commandRunner?: CommandRunner;
|
|
104
|
+
commandExists?: CommandExists;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Options shared by plain command-runner (Linux) providers. */
|
|
108
|
+
export interface CommandRunnerProviderOptions {
|
|
109
|
+
priority?: number;
|
|
110
|
+
commandRunner?: CommandRunner;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Base for macOS providers that read the clipboard via a namespace-wrapped
|
|
115
|
+
* command (osascript/pngpaste). Encapsulates the commandRunner/commandExists
|
|
116
|
+
* wiring, the command-availability check, and the shared read preamble
|
|
117
|
+
* (namespace wrap -> run -> fallback), so concrete providers only describe
|
|
118
|
+
* their command args and how to turn stdout into an image.
|
|
119
|
+
*/
|
|
120
|
+
export abstract class NamespacedCommandProvider implements ClipboardImageProvider {
|
|
121
|
+
readonly capabilities: ProviderCapabilities;
|
|
122
|
+
private readonly commandRunner: CommandRunner;
|
|
123
|
+
private readonly commandExists: CommandExists;
|
|
124
|
+
private readonly isAvailableFn: (context: ClipboardProviderContext) => boolean;
|
|
125
|
+
|
|
126
|
+
constructor(
|
|
127
|
+
capabilities: ProviderCapabilities,
|
|
128
|
+
private readonly commandName: string,
|
|
129
|
+
options: NamespacedCommandProviderOptions = {},
|
|
130
|
+
) {
|
|
131
|
+
this.capabilities = capabilities;
|
|
132
|
+
this.commandRunner = options.commandRunner ?? defaultCommandRunner;
|
|
133
|
+
this.commandExists = options.commandExists ?? defaultCommandExists;
|
|
134
|
+
this.isAvailableFn = createCommandAvailabilityChecker(this.commandName, this.commandExists);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
isAvailable(context: ClipboardProviderContext): boolean {
|
|
138
|
+
return this.isAvailableFn(context);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
read(context: ClipboardProviderContext): ClipboardReadResult {
|
|
142
|
+
const wrapped = buildNamespaceWrappedCommand(this.commandName, this.buildArgs(), context, this.commandExists);
|
|
143
|
+
const result = this.commandRunner(wrapped.command, wrapped.args, {
|
|
144
|
+
environment: context.environment,
|
|
145
|
+
maxBuffer: MAX_BUFFER_BYTES,
|
|
146
|
+
timeout: READ_TIMEOUT_MS,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const fallback = mapProviderReadFallback(result);
|
|
150
|
+
if (fallback) {
|
|
151
|
+
return fallback;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return this.readFromResult(result);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
protected abstract buildArgs(): readonly string[];
|
|
158
|
+
protected abstract readFromResult(result: CommandResult): ClipboardReadResult;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Base for Linux providers that read the clipboard via a fixed command (no
|
|
163
|
+
* namespace wrapping). Provides the commandRunner field, an always-available
|
|
164
|
+
* `isAvailable`, and a shared `runCommand` helper so concrete providers only
|
|
165
|
+
* implement `read`.
|
|
166
|
+
*/
|
|
167
|
+
export abstract class CommandRunnerProvider implements ClipboardImageProvider {
|
|
168
|
+
readonly capabilities: ProviderCapabilities;
|
|
169
|
+
protected readonly commandRunner: CommandRunner;
|
|
170
|
+
|
|
171
|
+
constructor(capabilities: ProviderCapabilities, options: CommandRunnerProviderOptions = {}) {
|
|
172
|
+
this.capabilities = capabilities;
|
|
173
|
+
this.commandRunner = options.commandRunner ?? defaultCommandRunner;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
isAvailable(_context: ClipboardProviderContext): boolean {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected runCommand(
|
|
181
|
+
command: string,
|
|
182
|
+
args: readonly string[],
|
|
183
|
+
context: ClipboardProviderContext,
|
|
184
|
+
timeout: number = READ_TIMEOUT_MS,
|
|
185
|
+
): CommandResult {
|
|
186
|
+
return this.commandRunner(command, args, {
|
|
187
|
+
environment: context.environment,
|
|
188
|
+
maxBuffer: MAX_BUFFER_BYTES,
|
|
189
|
+
timeout,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
abstract read(context: ClipboardProviderContext): ClipboardReadResult;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export type { ClipboardImageProvider };
|
|
@@ -1,81 +1,46 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const mimeTypes = listTypes.stdout
|
|
49
|
-
.toString("utf8")
|
|
50
|
-
.split(/\r?\n/)
|
|
51
|
-
.map((mimeType) => mimeType.trim())
|
|
52
|
-
.filter((mimeType) => mimeType.length > 0);
|
|
53
|
-
|
|
54
|
-
const selectedMimeType = selectPreferredImageMimeType(mimeTypes);
|
|
55
|
-
if (!selectedMimeType) {
|
|
56
|
-
return { available: true, image: null };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const imageData = this.commandRunner(
|
|
60
|
-
"wl-paste",
|
|
61
|
-
["--type", selectedMimeType, "--no-newline"],
|
|
62
|
-
{
|
|
63
|
-
environment: context.environment,
|
|
64
|
-
maxBuffer: MAX_BUFFER_BYTES,
|
|
65
|
-
timeout: READ_TIMEOUT_MS,
|
|
66
|
-
},
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
if (!imageData.ok || imageData.stdout.length === 0) {
|
|
70
|
-
return { available: true, image: null };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
available: true,
|
|
75
|
-
image: {
|
|
76
|
-
bytes: new Uint8Array(imageData.stdout),
|
|
77
|
-
mimeType: normalizeMimeType(selectedMimeType),
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
}
|
|
1
|
+
import { CommandRunnerProvider, providerEmptyImage, providerImageResult, providerUnavailable, LIST_TYPES_TIMEOUT_MS, parseMimeTypeList, type CommandRunnerProviderOptions, type ClipboardProviderContext, type ClipboardReadResult } from "./provider-helpers.js";
|
|
2
|
+
import { normalizeMimeType, selectPreferredImageMimeType } from "../image-mime.js";
|
|
3
|
+
|
|
4
|
+
export class WlPasteProvider extends CommandRunnerProvider {
|
|
5
|
+
constructor(options: CommandRunnerProviderOptions = {}) {
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
id: "wl-paste",
|
|
9
|
+
name: "wl-paste",
|
|
10
|
+
platforms: ["linux"],
|
|
11
|
+
priority: options.priority ?? 10,
|
|
12
|
+
},
|
|
13
|
+
options,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
read(context: ClipboardProviderContext): ClipboardReadResult {
|
|
18
|
+
const listTypes = this.runCommand("wl-paste", ["--list-types"], context, LIST_TYPES_TIMEOUT_MS);
|
|
19
|
+
if (listTypes.missingCommand) {
|
|
20
|
+
return providerUnavailable();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!listTypes.ok) {
|
|
24
|
+
return providerEmptyImage();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const mimeTypes = parseMimeTypeList(listTypes.stdout);
|
|
28
|
+
|
|
29
|
+
const selectedMimeType = selectPreferredImageMimeType(mimeTypes);
|
|
30
|
+
if (!selectedMimeType) {
|
|
31
|
+
return providerEmptyImage();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const imageData = this.runCommand(
|
|
35
|
+
"wl-paste",
|
|
36
|
+
["--type", selectedMimeType, "--no-newline"],
|
|
37
|
+
context,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (!imageData.ok || imageData.stdout.length === 0) {
|
|
41
|
+
return providerEmptyImage();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return providerImageResult(new Uint8Array(imageData.stdout), normalizeMimeType(selectedMimeType));
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/providers/xclip.ts
CHANGED
|
@@ -1,87 +1,51 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
.split(/\r?\n/)
|
|
53
|
-
.map((mimeType) => mimeType.trim())
|
|
54
|
-
.filter((mimeType) => mimeType.length > 0)
|
|
55
|
-
: [];
|
|
56
|
-
|
|
57
|
-
const preferredMimeType =
|
|
58
|
-
advertisedMimeTypes.length > 0 ? selectPreferredImageMimeType(advertisedMimeTypes) : null;
|
|
59
|
-
const mimeTypesToTry = preferredMimeType
|
|
60
|
-
? [preferredMimeType, ...SUPPORTED_IMAGE_MIME_TYPES]
|
|
61
|
-
: [...SUPPORTED_IMAGE_MIME_TYPES];
|
|
62
|
-
|
|
63
|
-
for (const mimeType of mimeTypesToTry) {
|
|
64
|
-
const imageData = this.commandRunner(
|
|
65
|
-
"xclip",
|
|
66
|
-
["-selection", "clipboard", "-t", mimeType, "-o"],
|
|
67
|
-
{
|
|
68
|
-
environment: context.environment,
|
|
69
|
-
maxBuffer: MAX_BUFFER_BYTES,
|
|
70
|
-
timeout: READ_TIMEOUT_MS,
|
|
71
|
-
},
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
if (imageData.ok && imageData.stdout.length > 0) {
|
|
75
|
-
return {
|
|
76
|
-
available: true,
|
|
77
|
-
image: {
|
|
78
|
-
bytes: new Uint8Array(imageData.stdout),
|
|
79
|
-
mimeType: normalizeMimeType(mimeType),
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return { available: true, image: null };
|
|
86
|
-
}
|
|
87
|
-
}
|
|
1
|
+
import { CommandRunnerProvider, providerEmptyImage, providerImageResult, providerUnavailable, LIST_TYPES_TIMEOUT_MS, parseMimeTypeList, type CommandRunnerProviderOptions, type ClipboardProviderContext, type ClipboardReadResult } from "./provider-helpers.js";
|
|
2
|
+
import { normalizeMimeType, selectPreferredImageMimeType, SUPPORTED_IMAGE_MIME_TYPES } from "../image-mime.js";
|
|
3
|
+
|
|
4
|
+
export class XclipProvider extends CommandRunnerProvider {
|
|
5
|
+
constructor(options: CommandRunnerProviderOptions = {}) {
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
id: "xclip",
|
|
9
|
+
name: "xclip",
|
|
10
|
+
platforms: ["linux"],
|
|
11
|
+
priority: options.priority ?? 20,
|
|
12
|
+
},
|
|
13
|
+
options,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
read(context: ClipboardProviderContext): ClipboardReadResult {
|
|
18
|
+
const targets = this.runCommand(
|
|
19
|
+
"xclip",
|
|
20
|
+
["-selection", "clipboard", "-t", "TARGETS", "-o"],
|
|
21
|
+
context,
|
|
22
|
+
LIST_TYPES_TIMEOUT_MS,
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
if (targets.missingCommand) {
|
|
26
|
+
return providerUnavailable();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const advertisedMimeTypes = targets.ok ? parseMimeTypeList(targets.stdout) : [];
|
|
30
|
+
|
|
31
|
+
const preferredMimeType =
|
|
32
|
+
advertisedMimeTypes.length > 0 ? selectPreferredImageMimeType(advertisedMimeTypes) : null;
|
|
33
|
+
const mimeTypesToTry = preferredMimeType
|
|
34
|
+
? [preferredMimeType, ...SUPPORTED_IMAGE_MIME_TYPES]
|
|
35
|
+
: [...SUPPORTED_IMAGE_MIME_TYPES];
|
|
36
|
+
|
|
37
|
+
for (const mimeType of mimeTypesToTry) {
|
|
38
|
+
const imageData = this.runCommand(
|
|
39
|
+
"xclip",
|
|
40
|
+
["-selection", "clipboard", "-t", mimeType, "-o"],
|
|
41
|
+
context,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (imageData.ok && imageData.stdout.length > 0) {
|
|
45
|
+
return providerImageResult(new Uint8Array(imageData.stdout), normalizeMimeType(mimeType));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return providerEmptyImage();
|
|
50
|
+
}
|
|
51
|
+
}
|