【QT特性技術講解】QPrinter、QPdf

前言

? ? ? ? QT對打印和PDF應用場景,做了簡單的封裝,復雜的功能還是得用第三方庫,打印功能簡單的文本可以不用PDF,涉及圖形的基本都要用到PDF。

Linux打印

? ? ? ? 隨著國產信創項目替換基于Linux的桌面系統國產信創系統,Linux桌面系統用的裝機量越來越多,打印功能的使用頻度也越來越高,以下分享Linux下的打印工具。

CPUS

??????????CUPS??(??Common UNIX Printing System??,通用UNIX打印系統)是 Linux 和類 UNIX 操作系統上事實標準的、開源的打印系統。在 2007 年被蘋果公司收購。蘋果macOS的打印系統也是基于 CUPS(Quartz+CUPS,Quartz將內容渲染為PDF格式?,再推送到CUPS進行打印)。

? ? ? ? 國產信創操作系統(麒麟kylin和統信UOS系統)默認安裝了CUPS,可以提供web、官方工具或者是第三方工具查看系統打印機信息。

web訪問

? ? ? ? 默認端口是631,創建打印機需要用戶名和密碼。

http://localhost:631/

在上圖中可以看到Local Printers中有一個CUPS-PDF,這是把打印內容輸出為PDF文件,CUPS默認是不安裝這個功能的,需要手動下載

sudo apt install cups-pdf

cups-pdf

配置文件:/etc/cups/cups-pdf.conf
配置文件中Out ${HOME}/PDF為pdf文件保存的路徑,可以修改為:Out /home/printpool

對于新手來說,web方式不是很好操作,以下介紹好用的工具。

system-config-printer

apt install system-config-printer

以下展示如何創建一個PD打印機

以上配置完成之后,打開一個待打印的文件,點擊打印按鈕之后,即可看到新增的打印機,如下圖

應用場景延伸

? ? ? ? 以上PDF打印機是可以創建很多的,但cups-pdf配置文件指向了統一的輸出目錄,如果需要多個cups-pdf,多個不同的輸出目錄,可以如下操作:

在/etc/cups目錄下拷貝cups-pdf.conf,比如生成cups-pdf-mypdf.conf,修改cups-pdf-mypdf中Out的輸出目錄即可,這個時候在web端我打馬賽克的地方可以看到這個PDF,但在system-config-printer工具中是不到的,不管沒關系,創建過程是一樣的,只需要修改設備URI即可,如下

命令行工具

lpstat -p -d: 列出所有打印機 (-p) 并顯示默認打印機 (-d)

lp <文件名>: 使用默認打印機打印文件

lp -d <打印機名> <文件名>: 指定打印機進行打印。
sudo lpadmin -p <打印機名稱> <關鍵參數>:創建打印機

sudo lpadmin -p MyPrinter -E -v ipp://192.168.1.100/ipp/port1 -m everywhere

連接類型??

??URI格式??

??示例??

PDF打印機cups-pdf:/cups-pdf:/

USB打印機

usb://vendor/model?serial=xxx

usb://HP/Deskjet?serial=123ABC

網絡IPP打印機

ipp://IP地址/ipp/print

ipp://192.168.1.100/ipp/print

Windows共享打印機

smb://用戶名:密碼@主機名/打印機共享名

smb://user:pass@WINPC/OfficePrinter

LPD協議打印機

lpd://IP地址/隊列名

lpd://192.168.1.101/L1

AppSocket打印機

socket://IP地址:端口

socket://192.168.1.102:9100

以ppd模板創建打印機

????????ppd模板文件默認生成在/etc/cups/ppd/目錄下,上面通過system-config-printer創建的【我的PDF打印機】在此目錄下會生成一個【我的PDF打印機.ppd】文件,以此作為模板即可生成配置一樣的打印機,如下

sudo lpadmin -p 我的打印機 -E -v cups-pdf:/ -P /etc/cups/ppd/我的PDF打印機.ppd

cups開發庫

sudo apt install cups libcups2-dev

編譯時加上-lcups

//列出所有打印機
#include <cups/cups.h>int main() {cups_dest_t *dests;int num_dests = cupsGetDests(&dests);  // 獲取打印機列表printf("找到 %d 臺打印機:\n", num_dests);for (int i = 0; i < num_dests; i++) {printf("%d. %s", i+1, dests[i].name);if (dests[i].is_default) printf(" [默認]");printf("\n");}cupsFreeDests(num_dests, dests);  // 釋放內存return 0;
}

以下是核心API

??函數??

??描述??

cupsGetDests()

獲取打印機列表

cupsPrintFile()

提交文件打印任務

cupsGetDefault()

獲取默認打印機名稱

cupsLastErrorString()

獲取最后一次錯誤的描述

cupsAddOption()

添加打印選項

cupsGetPPD()

獲取打印機的 PPD 文件路徑

cupsTempFile()

創建臨時文件

cupsMarkOptions()

驗證打印選項是否有效

window打印

? ? ? ? 傳統打印路徑依賴 ?GDI?(圖形設備接口),較老舊,現代路徑使用 ?XPS?(XML 打印規范,類似 PDF)。打印驅動直接與 GDI/XPS 交互。從這里可以看出window下與Linux和macOS完全不一樣,QT的接口封裝也不一樣,可能也是QT沒有對QPrinter進行深度的封裝的原因吧。

? ? ? ? 在國產信創項目推進過程中,很多客戶都會問:我的這些打印機都能在國產信創終端上使用嗎。第一反應通常是:打印機廠商提供有驅動的都可以用(很多老打印機廠商是不維護驅動的,這部分打印機無法在國產信創設備下使用)。但換個思路,提供一臺有老打印機驅動的window系統,結合以上分享的linux的cups-pdf打印機,把PDF文件傳輸到這個window系統下生成打印任務,即可解決”國產信創設備下使用不了老打印機“的問題。

? ? ? ? window下,QT的QPrinter支持調用系統級打印對話框來打印PDF文件,但不支持后臺命令行方式(打印機名稱+PDF文件名稱)打印PDF文件的!以下分享一個支持后臺命令行方式打印PDF文件的工具。

SumatraPDF

? ? ? ? 下載地址:Sumatra PDF reader download pagehttps://www.sumatrapdfreader.org/download-free-pdf-viewer配置環境變量之后,打印PDF文件的命令行如下

SumatraPDF.exe -print-to "Lexmark MX410de" "D:\myfile.pdf" > nul 2>&1

? ? ? ? 以上的分享也是希望點題:print和pdf分不開。?以下會分享一個qt樣例,從開發角度進一步了解兩者的關系:選擇并展示PDF內容,打印預覽PDF內容,打印PDF內容。

效果圖

功能詳細講解

????? ? ? ? QPdf核心接口是QPdfDocuments,可進行加載PDF、獲取PDF頁數、將 PDF 頁面渲染為圖像。

選擇PDF文件

調用了加載PDF、獲取PDF頁數兩個接口,代碼如下:

//頭文件
#include <QPdfDocument>
class MainWindow : public QMainWindow
{
private:QPdfDocument *pdfDoc;
};//cpp文件
#include <QStandardPaths>
void MainWindow::on_btnSelect_clicked()
{QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);//獲取桌面路徑QString file = QFileDialog::getOpenFileName(this,tr("Open PDF"), desktopPath, tr("PDF Files (*.pdf)"));if(file.isEmpty()) return;currentFile = file;pdfDoc->load(file);ui->spinBox->setMaximum(pdfDoc->pageCount());ui->spinBox->setValue(1);updatePreview();
}void MainWindow::updatePreview()
{if(pdfDoc->pageCount() <= 0) return;int page = ui->spinBox->value() - 1;QImage image = pdfDoc->render(page, ui->labelPreview->size());ui->labelPreview->setPixmap(QPixmap::fromImage(image));
}

打印預覽

? ? ? ? QPdf部分調用了獲取PDF頁數、將 PDF 頁面渲染為圖像兩個接口

? ? ? ? QPrinter部分調用了QPrintPreviewDialog彈出系統級的打印對話框,對話框上有打印按鈕,另外QPrintPreviewWidget可以顯示打印預覽框,但是風格比較簡潔,效果如下:

以下僅給出使用QPrintPreviewDialog的代碼:

//頭文件
#include <QPainter>
class MainWindow : public QMainWindow
{
private:QPrinter printer;
}//cpp文件
void MainWindow::on_actionPrintPreview_clicked()
{if (pdfDoc->pageCount() == 0) return; // 檢查是否有可打印內容// 創建打印預覽部件QPrintPreviewDialog preview(&printer, this);connect(&preview, &QPrintPreviewDialog::paintRequested,this, &MainWindow::printPreview);preview.exec();
}void MainWindow::printPreview()
{QPainter painter(&printer);painter.setRenderHints(QPainter::Antialiasing |QPainter::TextAntialiasing |QPainter::SmoothPixmapTransform,// 使用平滑變換繪制true);// 精確計算DPI縮放比例const double dpiScale = printer.logicalDpiX() / 72.0;painter.scale(dpiScale, dpiScale);// 高質量渲染PDF每頁內容for(int i = 0; i < pdfDoc->pageCount(); ++i) {if(i > 0) printer.newPage();QSizeF pageSize = pdfDoc->pagePointSize(i);// 將PDF頁面渲染為圖像QImage pageImage = pdfDoc->render(i, pageSize.toSize() * dpiScale);// 繪制到打印機painter.drawImage(QRectF(0, 0, pageSize.width(), pageSize.height()),pageImage,QRectF(0, 0, pageImage.width(), pageImage.height()));}
}

打印文件

? ? ? ? QPdf部分調用了獲取PDF頁數、將 PDF 頁面渲染為圖像兩個接口

? ? ? ? QPrinter部分調用了QPrintDialog彈出系統級的打印對話框,讓用戶選擇打印機之后進行打印

void MainWindow::on_btnPrint_clicked()
{if(currentFile.isEmpty()) {QMessageBox::warning(this, tr("Error"), tr("No PDF file selected"));return;}QPrintDialog dialog(&printer, this);if(dialog.exec() == QDialog::Accepted) {QPainter painter;if(!painter.begin(&printer)) {QMessageBox::critical(this, tr("Error"), tr("Failed to initialize printer"));return;}for(int i = 0; i < pdfDoc->pageCount(); ++i) {if(i > 0) printer.newPage();//QImage image = pdfDoc->render(i, printer.pageRect(QPrinter::Point).size());QSizeF sizeF = printer.pageRect(QPrinter::Point).size();QImage image = pdfDoc->render(i, sizeF.toSize());  // 顯式轉換為QSizepainter.drawImage(printer.pageRect(QPrinter::Point), image);}painter.end();}
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95562.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95562.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95562.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【大數據技術實戰】Flink+DS+Dinky 自動化構建數倉平臺

一、背景&#xff1a;企業數倉建設的現狀與挑戰在數字化轉型進入深水區的今天&#xff0c;數據已成為企業核心生產要素&#xff0c;而實時數倉作為 “數據驅動決策” 的關鍵載體&#xff0c;其建設水平直接決定企業在市場競爭中的響應速度與決策精度。根據 IDC《2024 年全球大數…

Python開篇:撬動未來的萬能鑰匙 —— 從入門到架構的全鏈路指南

Python&#xff1a;撬動未來的萬能鑰匙——從入門到架構的全鏈路指南 在技術的星空中&#xff0c;Python 是那顆永不隕落的超新星——它用簡潔的語法點燃創造之火&#xff0c;以龐大的生態鋪就革新之路。無論你身處哪個領域&#xff0c;這把鑰匙正在打開下一個時代的大門。2024…

【QT隨筆】事件過濾器(installEventFilter 和 eventFilter 的組合)之生命周期管理詳解

【QT隨筆】事件過濾器(installEventFilter 和 eventFilter 的組合)之生命周期管理詳解 上一章節中提到事件過濾器(Event Filter),用于處理特定事件。其中第二小節中提到了事件過濾器生命周期管理。本文將詳細解析事件過濾器生命周期管理這一部分的內容。 (關注不迷路哈!…

關于linux軟件編程12——網絡編程3

一、單循環服務器 特點:1.可以處理多個客戶端 (不能同時)2.效率不高//單循環服務器: socket bind listen while (1) {connfd accept();//通信 }特點:簡單 可以處理多客戶端 不能同時 二、并發服務器 --- 同時可以處理多個客戶端1、設置一個選項(開啟一個功能) ---讓地址重…

thinkphp6通過workerman使用websocket

安裝workerman依賴 composer require topthink/think-worker composer require topthink/think-worker1.0.* # 指定兼容版本?:ml-citation{ref"1,7" data"citationList"}config配置 config/worker.php <?php return [// 擴展自身需要的配置host …

Rust SQLx 開發指南:利用 Tokio 進行性能優化

在當今高并發的應用開發環境中&#xff0c;數據庫操作往往是性能瓶頸的主要來源之一。SQLx 作為一個純 Rust 編寫的異步 SQL 客戶端庫&#xff0c;通過與 Tokio 運行時深度集成&#xff0c;為開發者提供了處理數據庫 I/O 密集型操作的強大工具。本文將帶您深入了解如何利用這兩…

嵌入式硬件電路分析---AD采集電路

文章目錄摘要AD采集電路1AD采集電路2R77的真正作用是什么&#xff1f;理想與現實&#xff1a;為什么通常可以忽略R77的影響&#xff1f;摘要 AD采集 AD采集電路1 這是個人畫的簡化后的AD采集電路 這是一個AD檢測電路&#xff0c;R1是一個可變電阻&#xff0c;R2是根據R1的常用…

Python爬取nc數據

1、單文件爬取爬取該網站下的crupre.nc數據&#xff0c;如下使用requests庫&#xff0c;然后填寫網站的url&#xff1a;"http://clima-dods.ictp.it/regcm4/CLM45/crudata/"和需要下載的文件名&#xff1a;"crupre.nc"import requests import osdef downlo…

策略模式 + 工廠模式

策略模式&#xff1a;簡單來說解決的行為的封裝與選擇。如HandlerMapping&#xff0c;將 HTTP 請求映射到對應的處理器&#xff08;Controller 或方法&#xff09;。工廠模式&#xff1a;解決的是具有相同屬性的對象創建問題&#xff0c;如BeanFactory創建bean對象。解決的代碼…

Diamond基礎3:在線邏輯分析儀Reveal的使用

文章目錄1. 與ILA的區別2. 使用Reveal步驟3.Reveal注意事項4.傳送門1. 與ILA的區別 Reveal是Lattice Diamond集成開發環境用于在線監測信號的工具&#xff0c;ILA是xilinx的Vivado集成開發工具的在線邏輯分析儀&#xff0c;同Reveal一樣&#xff0c;均可以在項目運行過程中&am…

超適合程序員做知識整理的 AI 網站

這次要給大家分享一個超適合程序員做知識整理的 AI 網站 ——Notion AI&#xff0c;網址是Notion&#xff0c;它能把你隨手記的雜亂筆記、代碼片段、技術文檔&#xff0c;一鍵梳理成邏輯清晰的結構化內容&#xff0c;小索奇我用它整理 “Python 爬蟲知識點” 時&#xff0c;原本…

【 Selenium 爬蟲】2025年8月25日-pixabay 圖片采集

無惡意采集&#xff0c;取部分圖片用來做相冊測試的&#x1f604; 效果圖import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.la.selenium.utils.SeleniumUtil; import lombok.extern.slf4j.Slf4j; import o…

服務器托管需要注意什么事項?

服務器托管是企業IT基礎設施的關鍵環節&#xff0c;其穩定性和安全性直接影響業務連續性。需要注意下面這幾點&#xff01; 一、服務商與機房選擇 服務商資質 選擇持有ISP證書的合法服務商&#xff0c;優先考慮運營超5年、市場口碑佳的老牌公司&#xff0c;技術團隊需具備72…

微信小程序備忘

1.按鈕事件中想切換到tabBar中的鏈接用switchTab&#xff0c;不能用navigateTo&#xff1a;agentPage: function() { wx.switchTab({url: /pages/agent/agent}) },特別注意&#xff1a;微信小程序中所謂的自定義&#xff0c;并不是完全的自定義&#xff0c;在app.json中定義&a…

虛擬機NAT模式通過宿主機(Windows)上網不穩定解決辦法(無法上網)(將宿主機設置固定ip并配置dns)

文章目錄問題描述解決辦法分析**1. 問題的根本原因****(1) 宿主機動態IP的DNS配置問題****(2) NAT模式下的網絡依賴****(3) 自習室WiFi的潛在限制****2. 用戶操作的合理性分析****(1) 固定IP的作用****(2) 手動指定公共DNS的作用****3. 用戶懷疑的正確性****4. 其他可能原因的排…

基于 HTML、CSS 和 JavaScript 的智能圖像虛化系統

目錄 1 前言 2 技術實現 2.1 HTML&#xff1a;搭建頁面基礎結構 2.2 CSS&#xff1a;打造科技感視覺體驗 2.3 JavaScript&#xff1a;實現核心虛化功能 2.3.1 圖像上傳與初始化 2.3.2 實時虛化處理 2.3.3 圖像下載功能 3 完整代碼 4 運行結果 5 總結 1 前言 三大核…

PS更改圖像尺寸

新建文檔 1.左上角——新文件可以新建文檔2.文件——新建文檔3.快捷鍵CtrlN 對文件命名 輸入新文件名稱設置寬度和高度 設置文件的寬高&#xff0c;單位可以是像素、英寸、厘米等。還可以選擇文件方向或者是否使用畫板模式畫布背景色 一般顯示白色&#xff0c;也可以選擇其他顏…

分詞器詳解(一)

文章目錄&#x1f31f; 第0層&#xff1a;極簡版&#xff08;30秒理解&#xff09;核心公式生活比喻&#x1f4da; 第1層&#xff1a;基礎概念&#xff08;5分鐘理解&#xff09;1. 分詞器基礎1.1 分詞器的核心作用1.2 主流分詞算法對比2. 基礎實現2.1 BPE實現原理2.2 特殊標記…

推薦一個論文閱讀工具ivySCI

1.一些關于ivySCI的數據 &#xff08;摘自&#xff1a;吳焱紅&#xff0c;論文示范:ivySCI 在論文管理、閱讀和筆記中的體驗&#xff09; 1.科研人員花在文獻閱讀上的時間占總工作時間的 23%2.每年閱讀的文獻數量大概是 188 到 280 篇3.ivySCI 提供 Pad(iPad 和 Android) 和桌…

診斷服務器(Diagnostic Server)

在《SWS_Diagnostics.pdf》中,診斷服務器(Diagnostic Server) 是診斷管理(DM)的核心執行單元,聚焦 “軟件集群(SoftwareCluster)級診斷資源的獨立管控”,實現 UDS(ISO 14229-1)與 SOVD(ASAM 服務化診斷)的全流程診斷功能。以下結合文檔 7.3 節 “Diagnostic Serve…