[*] Предварительный просмотр PDF: при печати пользователь должен увидеть предварительный просмотр
pdf, но не должен быть в состоянии сохранить или загружать его. < /Li>
Silent Printing: билет на плиту (PDF) должен быть печатан непосредственно на
fivicy Princator, с помощью PRINTTER, с PRINTTER NO, не с PRIPTTER, с PRINTTER, не так. /> Блок виртуальных принтеров: виртуальные принтеры (например, Microsoft Print to
PDF, XPS, OneNote и т. Д.) Должны быть заблокированы - только реальные /физические принтеры
должны быть выбираемы. print
works).
[*] Данные о билетах поставляются в виде PDF, сгенерированного Codeigniter (используя
tcpdf).
[*] Когда я пытаюсь распечатать PDF молча, ничто не печатается, и я вижу, что
ошибки, такие как настройки печати. /> < /ul>
У меня есть код для фильтрации виртуальных принтеров, но основная проблема - достоверно печатать PDF молча и показывать предварительный просмотр, не позволяя сохранить /загрузить. /> Какой лучший способ тихо напечатать PDF на физический принтер в
Electron (или в другом рабочем столе), особенно когда PDF
сгенерирован веб -бэкэнд? /> Любые образцы, библиотеки или архитектурные предложения оценены!
Код: Выделить всё
const { app, BrowserWindow, ipcMain, shell } =
require('electron');
const path = require('path');
const fs = require('fs');
const os = require('os');
const { net } = require('electron');
const DEBUG_MODE = true; // Set to false in production
let mainWindow;
// Create the main application window
function createWindow() {
mainWindow = new BrowserWindow({
width: 1280,
height: 800,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
sandbox: false,
preload: path.join(__dirname, 'preload.js')
},
autoHideMenuBar: true
});
// Load your web application
mainWindow.loadURL('http://192.168.1.17/pawn/pawn_sew/');
// Open external links in default browser
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (!url.startsWith('http://192.168.1.17')) {
shell.openExternal(url);
return { action: 'deny' };
}
return { action: 'allow' };
});
}
// Main app initialization
app.whenReady().then(() => {
createWindow();
// FIXED: Using correct API to get printers in newer Electron
versions
setTimeout(() => {
try {
// In newer versions of Electron, getPrinters is on
webContents.getPrintersAsync()
// or mainWindow.webContents.print.getPrinterList() depending
on version
if (mainWindow.webContents.getPrinters) {
const printers = mainWindow.webContents.getPrinters();
logPrinters(printers);
} else if (mainWindow.webContents.getPrintersAsync) {
mainWindow.webContents.getPrintersAsync().then(logPrinters);
} else if (mainWindow.webContents.print &&
mainWindow.webContents.print.getPrinterList) {
mainWindow.webContents.print.getPrinterList().then(logPrinters);
}
} catch (err) {
console.error('Failed to get printers:', err);
}
}, 2000); // Wait for window to be ready
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
< /code>
Коды, связанные с выбором принтера < /p>
// Update the logPrinters function to show virtual printer status
function logPrinters(printers) {
console.log('Available printers:');
printers.forEach((printer, index) => {
const isVirtual = isVirtualPrinter(printer.name);
console.log(
`${index + 1}. ${printer.name} (Default: ${printer.isDefault}, Virtual: ${isVirtual ? 'Yes' : 'No'})`
);
});
}
// Add this function to identify virtual printers
function isVirtualPrinter(printerName) {
// Common virtual printer names (case-insensitive)
const virtualPrinterPatterns = [
/pdf/i,
/microsoft/i,
/adobe/i,
/xps/i,
/document writer/i,
/onedrive/i,
/fax/i,
/virtual/i,
/print to file/i,
/cloud/i,
/scan/i,
/onenote/i, // Added for OneNote
/anydesk/i, // Added for AnyDesk
/remote/i, // Common for remote printing solutions
/universal/i, // Often used in virtual print drivers
/bullzip/i, // Another common PDF printer
/cutepdf/i, // Common PDF printer
/foxit/i, // Foxit PDF printer
/doro/i // DoroEasy PDF
];
return virtualPrinterPatterns.some(pattern => pattern.test(printerName));
}
// Add this helper function to determine if a printer is suitable for pawn tickets
function isSuitablePrinter(printerName) {
const lowerName = printerName.toLowerCase();
// Skip POS/thermal printers that aren't suitable for pawn tickets
if (lowerName.includes('pos') ||
lowerName.includes('thermal') ||
lowerName.includes('receipt') ||
lowerName.includes('dot matrix')) {
console.log(`Skipping printer ${printerName} as it appears to be a thermal/POS printer`);
return false;
}
// Include standard printers
return true;
}
// Quit when all windows are closed (except on macOS)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
< /code>
pdf -печатный код, связанный с печати (я использовал чатгпт) < /p>
async function printWithWindows(pdfPath, printerName) {
return new Promise((resolve, reject) => {
const { exec } = require('child_process');
// Use the Windows 'print' command (works for some printers, not all)
// Note: This is a basic fallback and may not support all PDF features
const command = `PRINT /D:"${printerName}" "${pdfPath}"`;
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`Direct print error: ${error.message}`);
reject(error);
} else {
console.log('Direct Windows print completed successfully');
resolve(true);
}
});
});
}
// Update the silent-print-ticket handler
ipcMain.handle('silent-print-ticket', async (event, ticketUrl) => {
console.log('Received print request for:', ticketUrl);
const DEBUG_MODE = true; // Set to false in production
let tempPdfPath;
let printWindow;
try {
// 1. Download PDF
tempPdfPath = await downloadPdf(ticketUrl);
// Verify file exists before printing
if (!fs.existsSync(tempPdfPath)) {
throw new Error(`PDF file does not exist at ${tempPdfPath}`);
}
const fileStats = fs.statSync(tempPdfPath);
console.log(`PDF file size: ${fileStats.size} bytes`);
// 2. Create a window with proper PDF display capabilities
printWindow = new BrowserWindow({
width: 800,
height: 1100,
show: DEBUG_MODE,
webPreferences: {
plugins: true
}
});
if (DEBUG_MODE) {
printWindow.webContents.openDevTools();
}
// 3. Load the PDF directly
const pdfUrl = `file://${tempPdfPath.replace(/\\/g, '/')}`;
console.log(`Loading PDF from: ${pdfUrl}`);
await printWindow.loadURL(pdfUrl);
// Add event listeners to capture PDF loading issues
printWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription) => {
console.error(`Failed to load PDF: ${errorDescription} (${errorCode})`);
});
// 4. Give PDF time to render properly
await new Promise(resolve => setTimeout(resolve, 2000));
console.log('PDF loaded, preparing to print');
// 5. Get available printers
let printers = [];
try {
if (mainWindow.webContents.getPrinters) {
printers = mainWindow.webContents.getPrinters();
} else if (mainWindow.webContents.getPrintersAsync) {
printers = await mainWindow.webContents.getPrintersAsync();
} else if (mainWindow.webContents.print && mainWindow.webContents.print.getPrinterList) {
printers = await mainWindow.webContents.print.getPrinterList();
}
} catch (err) {
console.error('Failed to get printer list:', err);
throw new Error('Could not find any printers. Please check your printer connection and try again.');
}
// 6. Filter out virtual printers and thermal printers
const realPrinters = printers.filter(printer =>
!isVirtualPrinter(printer.name) && isSuitablePrinter(printer.name)
);
console.log('Suitable printers for pawn tickets:', realPrinters.map(p => p.name));
if (realPrinters.length === 0) {
throw new Error('No suitable printers found for pawn tickets. Please connect a standard printer.');
}
// 7. Sort printers prioritizing default printers
const sortedPrinters = [...realPrinters].sort((a, b) => {
return a.isDefault ? -1 : (b.isDefault ? 1 : 0);
});
console.log('Prioritized printer order:', sortedPrinters.map(p => p.name));
// 8. Try each printer until one succeeds - with standard Electron printing
let lastError = null;
for (const printer of sortedPrinters) {
try {
console.log(`Attempting to print to ${printer.name}...`);
// Check network printer access
if (printer.name.startsWith('\\')) {
const hasAccess = await checkPrinterAccess(printer.name);
if (!hasAccess) {
console.log(`No access to network printer: ${printer.name}, skipping...`);
continue;
}
}
// Try standard Electron print with A4 half portrait settings
const printResult = await printWindow.webContents.print({
silent: true,
printBackground: true,
deviceName: printer.name,
pageSize: {
width: 210000, // A4 width in microns
height: 148500 // A4 height / 2 in microns
},
landscape: false,
margins: {
marginType: 'custom',
top: 5000,
bottom: 5000,
left: 5000,
right: 5000
},
dpi: {
horizontal: 300,
vertical: 300
}
});
if (printResult) {
console.log(`Successfully printed to ${printer.name}`);
if (printWindow && !printWindow.isDestroyed()) {
printWindow.close();
}
fs.unlink(tempPdfPath, () => {});
return {
success: true,
printerName: printer.name,
message: `Document successfully sent to printer "${printer.name}".`
};
} else {
console.log(`Print to ${printer.name} returned false`);
throw new Error('Printer returned unsuccessful status');
}
} catch (printerError) {
console.error(`Failed to print to ${printer.name}:`, printerError.message);
lastError = printerError;
// Continue to next printer
}
}
// 9. If Electron printing failed for all printers, try Windows direct printing
console.log("All Electron print attempts failed. Trying Windows direct printing...");
for (const printer of sortedPrinters) {
try {
console.log(`Attempting Windows direct print to ${printer.name}...`);
await printWithWindows(tempPdfPath, printer.name);
console.log(`Successfully printed to ${printer.name} using Windows direct printing`);
if (printWindow && !printWindow.isDestroyed()) {
printWindow.close();
}
return {
success: true,
printerName: printer.name,
message: `Document successfully printed to "${printer.name}" using Windows direct printing.`
};
} catch (winError) {
console.error(`Windows direct print to ${printer.name} failed:`, winError.message);
// Continue to next printer
}
}
// 10. Last resort: Show print dialog
if (DEBUG_MODE) {
console.log("All automatic print attempts failed. Trying with system dialog...");
const dialogResult = await printWindow.webContents.print();
if (dialogResult) {
console.log("Print succeeded with system dialog");
if (printWindow && !printWindow.isDestroyed()) {
printWindow.close();
}
fs.unlink(tempPdfPath, () => {});
return {
success: true,
message: "Document printed successfully using system dialog."
};
}
}
// If we get here, all methods failed
throw new Error('All print methods failed. Please check your printer connections and try again.');
} catch (error) {
console.error('Print error:', error.message);
if (printWindow && !printWindow.isDestroyed()) {
printWindow.close();
}
if (tempPdfPath) {
fs.unlink(tempPdfPath, () => {});
}
return {
success: false,
error: error.message,
userFriendlyMessage: `Printing failed: ${error.message}. Please check your printer connections and try again.`,
retryable: true
};
}
});
Available printers:
OneNote for Windows 10 (Default: false, Virtual: Yes)
[*]POS-80 (Default: false, Virtual: No)
Microsoft Автор документов XPS (по умолчанию: false, virtual: yes) < /li>
microsoft print to pdf (по умолчанию: false, virtual: yes) < /li>
Факс (по умолчанию: false, virtual: yes) < /li>
anydesk printer (default: false, virtual: yes) < /li>
hiputs-pryctors \p \p \p xpirtins ricturets \p \p \p xpirtuctors \p xp \p rictuts-prytry-prytrics. Tank 310 Series (копия 1) (по умолчанию: true, virtual: no) Получен запрос печати для:
http://192.168.1.17/pawn/pawn_sew/swe_ticket.pdf Pdf Загружено
успешно (8038 байт). />file://c:/Users/admini~1/appdata/local/temp/ticket_1745819614508.pdf
•10416:0428/112335.468:error:console(1)] «запрос autofill.enable
Fall. {"Code":-32601, "Сообщение": "'AutoFill.Enable' не найден"} ",
Источник:
devtools://devtools/bundled/core/protocol_client/protocol_client.js
(1) [10416: 0428/11233.4.463.4.4.463: 4.68: 4.4.463: 4.4.4.463: 4.63.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.63: 4.4.4.4. "Запрос
autofill.setAddresses не удался.
"Code"! PDF загружен, готовясь к печати Printer Printer POS-80, поскольку он
, по-видимому, является тепловым /POS-принтером, подходящими принтерами для пешки
Билеты: ['\\ accodn-pc \ hp чернил 310 серия (копирование 1)']
Приоритетный заказ принтера: ['\\ accounts-pc \ hp ink neer 310 series
(Copited 1)' Printing to to to to to to to to to to to to hp ink neer 310 series arest nears
(cope 1). \ Accounts-PC \ HP Ink Tank 310
Series (копия 1) ... Проверка доступа к сети Path: \ Accounts-PC
Успешно доступный путь сети: \ accounts-pc print to
\ accounts-pc \ hp ink tank 310 series (копия 1). Неудачный статус. Все попытки электронного печати
потерпели неудачу. Попробуйте Windows Direct Printing ... ...
Попытка Windows Direct Print to \ accounts-pc \ hp чернила бак 310
series (копия 1) ...
ows прямая печать прямой печати Чернильный бак 310
Series (копия 1) Использование Windows Direct Printing
^110416:0428/112337.075:error:device_event_log_impl.cc(202)) \ Accounts-PC \ HP Ink Tank 310 Series (копирование 1)
(тип назначения Klocal): Размер содержания пуст ps d: \ softmaster
projects \ pawning \ pawn-electron-app> < /li>
< /ol>
< /blockquote>
Подробнее здесь: https://stackoverflow.com/questions/795 ... lectron-fo