feat: enhance ImageMagick installation process and update documentation

- Added functions to resolve Homebrew and Linux escalation commands for ImageMagick installation.
- Improved error handling and logging for manual installation steps.
- Updated download URLs for ImageMagick based on the platform.
- Enhanced user interface messages to clarify installation steps for different operating systems.
- Adjusted CPU worker count in document extraction for better performance.
This commit is contained in:
sudipnext 2026-03-30 20:21:15 +05:45
parent 6a6afc7ab7
commit 691d0f62e8
5 changed files with 115 additions and 16 deletions

9
electron/.gitignore vendored
View file

@ -21,6 +21,13 @@ app_dist
resources/fastapi
resources/nextjs
dist
eng.traineddata
servers/fastapi/build/
servers/fastapi/dist/
servers/fastapi/fastembed_cache/
electron/.cache/
electron/.cache/export-runtime/
electron/.cache/export-runtime/
*.pkg
*.toc
*.zip
*.pyc

View file

@ -20,6 +20,7 @@ import {
import { getSetupStatus } from "../utils/setup-dependencies";
import {
getImageMagickDownloadUrl,
getImageMagickManualInstallCommands,
isImageMagickInstalled,
} from "../utils/imagemagick-check";
@ -72,6 +73,33 @@ function commandExists(command: string, versionArgs: string[] = ["--version"]):
return result.status === 0;
}
function resolveBrewCommand(): string | null {
if (commandExists("brew")) {
return "brew";
}
const candidates = ["/opt/homebrew/bin/brew", "/usr/local/bin/brew"];
for (const candidate of candidates) {
if (fs.existsSync(candidate)) {
return candidate;
}
}
return null;
}
function resolveLinuxEscalationCommand(): string | null {
if (commandExists("pkexec", ["--version"])) return "pkexec";
if (commandExists("sudo", ["-V"])) return "sudo";
return null;
}
function logManualImageMagickCommands(wc: WebContents) {
for (const line of getImageMagickManualInstallCommands()) {
const level = line.endsWith(":") ? "info" : "cmd";
sendImageMagickLog(wc, level, line);
}
}
function runInstallCommand(
wc: WebContents,
command: string,
@ -210,7 +238,18 @@ export function setupSetupInstallHandlers() {
if (process.platform === "linux") {
if (commandExists("apt-get")) {
await runInstallCommand(wc, "pkexec", [
const escalator = resolveLinuxEscalationCommand();
if (!escalator) {
throw new Error(
"Neither pkexec nor sudo is available to run apt-get install."
);
}
await runInstallCommand(wc, escalator, [
"apt-get",
"update",
]);
await runInstallCommand(wc, escalator, [
"apt-get",
"install",
"-y",
@ -218,17 +257,30 @@ export function setupSetupInstallHandlers() {
]);
} else {
throw new Error(
"apt-get is unavailable. Install ImageMagick manually from the official download page."
"apt-get is unavailable. Install ImageMagick manually using your package manager."
);
}
} else if (process.platform === "darwin") {
if (commandExists("brew")) {
await runInstallCommand(wc, "brew", ["install", "imagemagick"]);
} else {
let brewCommand = resolveBrewCommand();
if (!brewCommand) {
sendImageMagickLog(
wc,
"info",
"Homebrew not found. Installing Homebrew first..."
);
const installHomebrewCommand =
'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"';
await runInstallCommand(wc, "/bin/bash", ["-c", installHomebrewCommand]);
brewCommand = resolveBrewCommand();
}
if (!brewCommand) {
throw new Error(
"Homebrew is not installed. Install ImageMagick manually from the official download page."
"Homebrew installation completed, but brew was not found on PATH."
);
}
await runInstallCommand(wc, brewCommand, ["install", "imagemagick"]);
} else if (process.platform === "win32") {
if (commandExists("choco", ["-v"])) {
await runInstallCommand(wc, "choco", [
@ -238,7 +290,7 @@ export function setupSetupInstallHandlers() {
]);
} else {
throw new Error(
"Chocolatey is not installed. Install ImageMagick manually from the official download page."
"Chocolatey is not installed. Falling back to direct installer download."
);
}
} else {
@ -253,14 +305,21 @@ export function setupSetupInstallHandlers() {
const message =
error instanceof Error ? error.message : "ImageMagick install failed";
sendImageMagickLog(wc, "error", message);
logManualImageMagickCommands(wc);
const downloadUrl = getImageMagickDownloadUrl();
sendImageMagickLog(
wc,
"info",
`Falling back to manual install page: ${downloadUrl}`
`Opening manual install link: ${downloadUrl}`
);
await shell.openExternal(downloadUrl);
return { ok: true };
sendImageMagickProgress(
wc,
"error",
undefined,
"Finish manual installation, then click Retry."
);
return { ok: false, error: message };
}
}
);

View file

@ -18,10 +18,34 @@ export function isImageMagickInstalled(): boolean {
export function getImageMagickDownloadUrl(): string {
if (process.platform === "win32") {
return "https://imagemagick.org/script/download.php#windows";
return "https://imagemagick.org/archive/binaries/ImageMagick-7.1.2-18-Q16-HDRI-x64-dll.exe";
}
if (process.platform === "darwin") {
return "https://imagemagick.org/script/download.php#macosx";
return "https://brew.sh/";
}
return "https://imagemagick.org/script/download.php#linux";
}
export function getImageMagickManualInstallCommands(): string[] {
if (process.platform === "win32") {
return [
"Download and run the installer:",
getImageMagickDownloadUrl(),
];
}
if (process.platform === "darwin") {
return [
"Install Homebrew:",
'/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
"Install ImageMagick:",
"brew install imagemagick",
];
}
return [
"Install ImageMagick:",
"sudo apt-get update",
"sudo apt-get install -y imagemagick",
];
}

View file

@ -70,7 +70,7 @@ const ocrEnabled = parseBool(readArg("--ocr-enabled"), true);
const dpi = toNumber(readArg("--dpi"), 150, 72, 600);
const numWorkers = toNumber(
readArg("--num-workers"),
Math.max(os.cpus().length - 4, 1),
Math.max(os.cpus().length - 2, 1),
1,
64
);

View file

@ -288,7 +288,7 @@
? '<strong>Presenton</strong> uses LibreOffice to generate custom templates from PPTX files.'
: step === 'chrome'
? '<strong>Presenton</strong> uses Chromium for export and slide rendering. Download it now (~150 MB).'
: '<strong>Presenton</strong> uses ImageMagick for OCR/document conversion support. We will try automatic installation first, then open the download page if package manager tools are unavailable.';
: '<strong>Presenton</strong> uses ImageMagick for OCR/document conversion support. Linux uses apt, macOS installs Homebrew first (if needed) and then runs brew install imagemagick, and Windows uses Chocolatey with a direct installer fallback.';
document.getElementById('btn-install').onclick = () => startInstall(step);
document.getElementById('btn-skip').onclick = () => handleSkip();
showState('prompt');
@ -315,8 +315,17 @@
});
} else {
document.getElementById('dl-heading').textContent = 'Installing ImageMagick';
document.getElementById('dl-phase').textContent = 'Automatic install (apt/brew/choco) with fallback to manual download';
window.setupInstaller.installImageMagick().then(() => {
document.getElementById('dl-phase').textContent = 'Linux: apt-get | macOS: Homebrew + brew install | Windows: choco or direct installer';
window.setupInstaller.installImageMagick().then((installResult) => {
if (!installResult || !installResult.ok) {
if (currentStep !== 'imagemagick') return;
document.getElementById('err-msg').textContent = installResult?.error || 'ImageMagick installation needs manual completion. Follow the shown commands and then click Retry.';
showState('error');
document.getElementById('btn-retry').onclick = () => startInstall('imagemagick');
document.getElementById('btn-skip-error').onclick = () => nextOrDone();
return;
}
window.setupInstaller.checkImageMagick().then(res => {
if (!res.ok && currentStep === 'imagemagick') {
document.getElementById('err-msg').textContent = res.error || 'ImageMagick is not installed yet.';