領碼方案|Windows 下 PLT → PDF 轉換服務超級完整版:異步、權限、進度

摘要

面向 Windows 平臺,使用 ASP.NET Core Web API 結合 Ghostscript.NET 庫,實現 PLT(HPGL)→PDF 的純庫調用轉換,無需外部進程。支持同步與異步模式,采用 JWT+RBAC 進行權限治理,任務狀態存儲于 Redis,后臺服務并行處理并通過 SSE/WebSocket 或輪詢實時推送進度。集成 iText7 對生成 PDF 添加半透明水印,輸出可插拔至本地、S3、Azure Blob 等存儲。容器化部署于 Windows Containers 或 Kubernetes,結合 HPA 彈性伸縮與 Serilog+Prometheus+Grafana 可觀測性,滿足高并發、安全、可運維的文件轉換需求。

關鍵字

  • Ghostscript.NET
  • 異步轉換
  • 權限治理
  • 進度推送
  • Redis 存儲
  • Kubernetes 部署

一、組件安裝與環境準備

  • 操作系統:Windows 10/11 或 Windows Server 2019/2022
  • .NET 環境:安裝 .NET 7.0 SDK 與對應 ASP.NET Core Runtime
  • Ghostscript(含 PLT/HPGL 支持)
    • 安裝 Ghostscript for Windows,確保包含 gsdll32.dll/gsdll64.dll
    • 將安裝目錄(例如 C:\Program Files\gs\gs9.xxx\bin)加入系統 PATH
  • NuGet 依賴:
    Install-Package Ghostscript.NET
    Install-Package Ghostscript.NET.Rasterizer   # 可選:預覽
    Install-Package StackExchange.Redis
    Install-Package itext7                       # 或 PdfSharpCore
    Install-Package AWSSDK.S3                    # 可選:S3 存儲
    Install-Package Azure.Storage.Blobs          # 可選:Azure Blob
    Install-Package Hangfire.Core Hangfire.AspNetCore  # 可選:任務調度
    
  • Redis 服務:安裝 Memurai 或社區版 Redis for Windows,啟動并確認 localhost:6379 可訪問
  • 開發工具:Visual Studio 2022 或 VS Code + C# 擴展

二、核心 HTTP 接口

  1. POST /plt/upload

    • 參數:IFormFile filestring projectIdstring mode = "async"
    • 返回:sync→{ downloadUrl };async→{ taskId }
  2. GET /plt/status/{taskId}

    • 返回:{ taskId, status, progress, outputName, message }
  3. GET /plt/download/{fileName}

    • 下載生成的 PDF
  4. GET /plt/list

    • 參數:projectId, page, size
    • 返回:歷史轉換記錄列表
  5. POST /plt/uploadConverted

    • 上傳外部已轉換 PDF,返回 { url }
  6. GET /auth/check

    • 校驗當前用戶對項目的 convert/download 權限

三、同步與異步模式

  • 同步(sync)

    • 上傳后在當前請求里調用 Ghostscript.NET 直接轉換并水印
    • 阻塞等待完成,返回下載鏈接
  • 異步(async)

    • 上傳后立即返回 taskId
    • 后臺由 BackgroundService 或 Hangfire 從隊列取任務執行
    • 前端通過輪詢或 SSE/WebSocket 獲取實時進度

四、權限治理

  • 鑒權:JWT + OAuth2 公鑰驗證
  • 授權:Policy-Based Authorization + RBAC + 項目域校驗
  • 中間件/過濾器解析 Token,校驗用戶角色、projectId 與操作類型
  • 未授權訪問返回 HTTP 403

五、任務狀態管理與存儲

  • 領域模型 TaskStatusDto

    • TaskIdStatus(PENDING/PROCESSING/DONE/FAILED)
    • Progress (0–100)、FileNameOutputNameMessage
  • 接口 ITaskStatusStore

    Task CreateAsync(TaskStatusDto status);
    Task UpdateAsync(string taskId, Action<TaskStatusDto> update);
    Task<TaskStatusDto?> GetAsync(string taskId);
    ValueTask<(string taskId, string inputPath, string outputPath)> DequeueAsync(CancellationToken ct);
    
  • Redis 實現:StackExchange.Redis 保存 JSON,設置 TTL 自動清理

  • 存儲輸出:本地目錄 / AWS S3 / Azure Blob / MinIO 插件化替換


六、PLT → PDF 轉換與水印(無外部進程)

1. 轉換接口定義

public interface IPltToPdfConverter
{Task ConvertAsync(string inputPath,string outputPath,IProgress<(int percent, string message)> progress,CancellationToken cancellationToken);
}

2. Ghostscript.NET 實現

using Ghostscript.NET;
using Ghostscript.NET.GhostscriptProcessing;public class GhostscriptNetConverter : IPltToPdfConverter
{private readonly GhostscriptVersionInfo _versionInfo;public GhostscriptNetConverter(){_versionInfo = GhostscriptVersionInfo.GetLastInstalledVersion()?? throw new InvalidOperationException("未檢測到 Ghostscript 安裝");}public Task ConvertAsync(string inputPath,string outputPath,IProgress<(int, string)> progress,CancellationToken cancellationToken) =>Task.Run(() =>{progress?.Report((10, "初始化 Ghostscript"));var switches = new[]{"-q", "-dNOPAUSE", "-dBATCH", "-dSAFER","-sDEVICE=pdfwrite",$"-sOutputFile={outputPath}",inputPath};using var processor = new GhostscriptProcessor(_versionInfo, true);processor.StartProcessing(switches,new GhostscriptProcessorTextDelegate(line =>{progress?.Report((50, "轉換進行中…"));}));progress?.Report((100, "轉換完成"));}, cancellationToken);
}

3. PDF 水印服務

using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;public class PdfWatermarkService
{public void ApplyWatermark(string pdfPath, string watermarkText){var tmpPath = pdfPath + ".tmp";using var reader = new PdfReader(pdfPath);using var writer = new PdfWriter(tmpPath);using var pdf    = new PdfDocument(reader, writer);for (int i = 1; i <= pdf.GetNumberOfPages(); i++){var canvas = new PdfCanvas(pdf.GetPage(i));canvas.SetFontAndSize(PdfFontFactory.CreateFont(), 36).SetFillColorGray(0.5f).BeginText().MoveText(200, 400).ShowText(watermarkText).EndText();}pdf.Close();File.Replace(tmpPath, pdfPath, null);}
}

七、后臺任務與進度推送

public class PltConversionJob : BackgroundService
{private readonly IPltToPdfConverter _converter;private readonly ITaskStatusStore  _store;private readonly PdfWatermarkService _watermarker;public PltConversionJob(IPltToPdfConverter converter,ITaskStatusStore store,PdfWatermarkService watermarker){_converter   = converter;_store       = store;_watermarker = watermarker;}protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){var (taskId, input, output) = await _store.DequeueAsync(stoppingToken);await _store.UpdateAsync(taskId, s => { s.Status = "PROCESSING"; s.Progress = 0; s.Message = "開始轉換"; });try{await _converter.ConvertAsync(input, output,new Progress<(int, string)>(p =>_store.UpdateAsync(taskId, s => { s.Progress = p.Item1; s.Message = p.Item2; })),stoppingToken);_watermarker.ApplyWatermark(output, "CONFIDENTIAL");await _store.UpdateAsync(taskId, s =>{s.Status     = "DONE";s.Progress   = 100;s.OutputName = Path.GetFileName(output);s.Message    = "完成";});}catch (Exception ex){await _store.UpdateAsync(taskId, s => { s.Status = "FAILED"; s.Message = ex.Message; });}}}
}

八、配置示例(appsettings.json)

{"Plt": {"TempDirectory": "C:\\plt\\tmp","OutputDirectory": "C:\\plt\\out"},"Storage": {"Type": "Local","Local": { "RootPath": "C:\\plt\\out" }},"Redis": { "Configuration": "localhost:6379" },"Async": { "MaxConcurrentTasks": 8, "QueueCapacity": 200 },"Jwt": { "Authority": "https://auth.example.com", "Audience": "plt-api" },"Watermark": { "Enabled": true, "Text": "CONFIDENTIAL", "Opacity": 0.15, "FontSize": 36 },"Security": { "RateLimitQps": 50, "MaxUploadMb": 50 }
}

九、前端集成

  • 技術棧:Vue/React + Axios
  • 上傳:FormData POST /plt/upload
  • 實時進度:setInterval 調 /plt/status/{taskId} 或 SSE/WebSocket
  • 下載:window.location.href = '/plt/download/' + outputName

十、部署與運維

  • 容器化:Windows Containers(或 Linux 容器亦可加載 Ghostscript DLL)
  • Kubernetes:Windows 節點組 + ConfigMap/Secret + PVC
  • 彈性伸縮:HPA 按 CPU 與隊列長度自動擴容
  • 安全:容器非管理員運行;Ghostscript 使用 -dSAFER;上傳文件安全掃描
  • 監控:Serilog + Prometheus + Grafana,關注 QPS、成功率、P95、隊列長度、失敗原因 Top N

十一、常見問題與優化

  • 進度不精準:結合文件規模或并行分片估算
  • I/O 瓶頸:將臨時目錄掛載到 RAM Disk
  • 多格式支持:擴展輸出為 PDF/A、PNG、SVG
  • 無服務器化:小文件可遷移至 Azure Functions/AWS Lambda
  • 水印增強:動態二維碼、PDF 數字簽名
  • CI/CD:GitHub Actions + Azure DevOps 壓測
  • 前端體驗:可視化進度條、失敗自動重試、歷史記錄查看

更多架構細節與實踐優化,歡迎交流!

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

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

相關文章

瀏覽器兼容性問題全解:CSS 前綴、Grid/Flex 布局兼容方案與跨瀏覽器調試技巧

1. 瀏覽器兼容性與前綴問題 不同瀏覽器&#xff08;尤其是老版本 IE、Edge、Safari&#xff09;對新特性&#xff08;比如 CSS 變量、Grid、Flex 等&#xff09;的支持程度不一&#xff0c;需要使用廠商前綴&#xff08;-webkit-、-moz- 等&#xff09;或降級方案。新手往往忽…

【Android View】事件分發機制

參考文獻 https://juejin.cn/post/6844904041487532045https://juejin.cn/post/6844903894103883789#heading-12https://www.jianshu.com/p/dea72779a6b7 文章目錄

【大數據相關】ClickHouse命令行與SQL語法詳解

ClickHouse命令行與SQL語法詳解一、ClickHouse命令行與SQL語法詳解第一部分&#xff1a;ClickHouse SQL 命令行客戶端 (clickhouse-client)1. 基礎連接2. 核心命令行參數3. 數據導入與導出實戰第二部分&#xff1a;ClickHouse SQL 語法詳解1. DDL (數據定義語言)2. DML (數據操…

學習日記-CSS-day53-9.11

1.CSS介紹知識點核心內容重點CSS定義層疊樣式表&#xff0c;用于內容修飾和樣式展現英文全稱cascading style sheetsCSS作用實現HTML內容與樣式分離&#xff0c;提高開發效率對比傳統HTML元素單獨設置樣式的低效方式學習建議掌握常用功能即可&#xff0c;重點在打通前后端數據通…

Maven中optional的作用

目的&#xff1a; 控制依賴傳遞 &#xff1a;將依賴標記為可選&#xff0c;這樣當其他模塊依賴common-component時&#xff0c;不會自動繼承Elasticsearch依賴。這遵循了"依賴最小化"原則&#xff0c;避免不必要的庫被引入到不需要它們的模塊中。模塊化設計 &#xf…

藍橋杯算法之基礎知識(7)---排序題的快排和歸并排序

一、快排》快排方法&#xff0c;就三步1.隨便選一個值作為基準值x2.拿選中的這個x值劃分隊列為左右兩個區間&#xff08;左邊的都小于x&#xff0c;右邊的都大于x&#xff09;3.然后遞歸左區間和右區間就行》代碼舉例&#xff1a;#qs排序#1 6 7 8 6 5 4 #先找比較點&#xff0c…

緩存未命中

緩存未命中&#xff08;Cache Miss&#xff09; 發生在 CPU 訪問某塊內存時&#xff0c;該地址不在當前緩存&#xff08;L1/L2/L3&#xff09;中&#xff0c;導致程序被迫從更慢的內存&#xff08;RAM&#xff09;讀取數據&#xff0c;嚴重拖慢程序執行速度。 &#x1f4cd; 一…

AR眼鏡:化工安全生產的技術革命

在石化企業的壓縮機組巡檢中&#xff0c;佩戴AR眼鏡的巡檢員眼前實時顯示著設備溫度場分布和振動頻譜曲線&#xff0c;單臺設備巡檢時間從45分鐘縮短至18分鐘。這不僅是效率的提升&#xff0c;更是化工安全生產的一場智能革命。一、行業痛點&#xff1a;傳統化工巡檢的困境與挑…

消息中間件RabbitMQ(從入門到精通)

RabbitMQ概念_MQ 消息隊列 MQ全稱Message Queue(消息隊列),是在消息的傳輸過程中保存消息的容器。多用于系統之間的異步通信。 同步通信相當于兩個人當面對話,你一言我一語。必須及時回復 異步通信相當于通過第三方轉述對話,可能有消息的延遲,但不需要二人時刻保持聯系。…

前端學習之后端java小白(五)之多表查詢/事務

一、多表查詢概念二、概述 1. 內連接隱式內連接 SELECT 字段列表 FROM 表1&#xff0c;表2... WHERE 條件顯示內連接SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 條件2. 外連接 左外連接SELECT 列名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 連接條件;右外連接SELECT 列名…

Java全棧學習筆記34

# JDBCjava database connection Java 數據庫連接技術## JDBC 驅動程序如果需要通過jdbc技術連接關系型數據庫&#xff0c;就需要為jdbc提供一個該數據庫的驅動。驅動程序由對應的數據庫廠商提供。mysql提供了針對于各種語言的驅動程序。去官網下載和java相關的驅動即可## JDB…

如何為MySQL中的JSON字段設置索引

背景 MySQL在2015年中發布的5.7.8版本中首次引入了JSON數據類型。自此&#xff0c;它成了一種逃離嚴格列定義的方式&#xff0c;可以存儲各種形狀和大小的JSON文檔&#xff0c;例如審計日志、配置信息、第三方數據包、用戶自定義字段等。 雖然MySQL提供了讀寫JSON數據的函數&am…

【學習日記】

1.上午看了會面經&#xff0c;八股&#xff0c;很多看不懂1.5排查本地mysql服務啟動問題2.刷了兩道題翻轉二叉樹的Dfs和bfs遞歸方法&#xff0c;看了幾分鐘看懂了&#xff0c;一開始刷題&#xff0c;沒有這種感覺&#xff0c;可能思維上升了3.下午做了會ppt4.看了ssm的一個gith…

本地大模型部署指南-Ollama與HuggingFace對比

在本地部署大模型時&#xff0c;用 Ollama 和 Hugging Face (HF) 確實有很大區別&#xff0c;涉及系統、硬件、訓練、推理方式&#xff0c;以及能否查看模型源代碼。下面我分幾個維度說明&#xff1a; 系統和安裝 Ollama 定位是「開箱即用」的本地大模型運行環境。 自帶運行時&…

河北周邊有哪些比較靠譜的智算中心?

河北省通過算力普惠、綠色能源、數據開放、金融支持四大支柱政策&#xff0c;推動智算中心高質量發展。河北及周邊地區的智算中心已形成高可靠性、先進技術和戰略協同的布局。那么&#xff0c;河北周邊有哪些比較靠譜的智算中心&#xff1f;一、河北周邊智算中心盤點?1、尚航懷…

電動汽車充電標準之 — 國標 GB/T 18487《電動汽車傳導充電系統》 簡介

GB/T 18487 的全稱是 《電動汽車傳導充電系統》 &#xff0c;它是中國電動汽車充電領域最基礎、最核心的國家標準之一。該標準規定了電動汽車傳導充電系統的通用要求、通信協議、安全要求等&#xff0c;是整個中國充電基礎設施建設的基石。 與您之前了解的IEC 61851類似&#x…

溫濕度傳感器如何守護工業制造?

在工業制造、農業養殖、倉儲物流乃至文物保護等領域&#xff0c;環境溫濕度的精確監測是保障品質與安全的關鍵。溫濕度傳感器作為無聲的守護者&#xff0c;如何通過穩定可靠的數據采集&#xff0c;為現代工業生產的精細化與智能化管理提供堅實基礎&#xff1f;本文將深入探討其…

破壁·融合·共贏:杭州大成慧谷基金與涉海科技混改項目公司正式啟航!

2025 年 7 月 15 日,一家融合國企基金實力與民企創新活力的混合所有制項目公司正式誕生——由杭州大成慧谷股權投資基金管理有限公司與山東涉海海洋生物科技有限公司共同出資設立的武創慧聚創芯科學技術(上海)有限公司,當日完成法律合規手續。此前,上海武創大智高新技術集團副總…

洛谷 P1271 【深基9.例1】選舉學生會-普及-

P1271 【深基9.例1】選舉學生會 題目描述 學校正在選舉學生會成員&#xff0c;有 nnn&#xff08;1≤n≤9991 \le n\le 9991≤n≤999&#xff09;名候選人&#xff0c;每名候選人編號分別從 111 到 nnn&#xff0c;現在收集到了 mmm&#xff08;1≤m≤20000001 \le m \le 20000…

【AI】AI 評測入門(二):Prompt 迭代實戰從“能跑通”到“能落地”

“Prompt 不是寫出來的&#xff0c;是測出來的。” ——這是我迭代 5 個版本后&#xff0c;最深的體悟。 上一篇《AI 評測入門&#xff08;一&#xff09;&#xff1a;先搞懂你的數據集)》&#xff0c;我們講了標簽體系、自測集、評測集、Langfuse 數據結構化——那是 AI 評測的…