form实现pdf文件转换成jpg文件

说明:
我希望将pdf文件转换成jpg文件
请去下载并安装 Ghostscript,gs10050w64.exe
配置环境变量:D:\Program Files\gs\gs10.05.0\bin
本地pdf路径:C:\Users\wangrusheng\Documents\name.pdf
输出文件目录:C:\Users\wangrusheng\Documents\PdfToJpgOutput
效果图:
在这里插入图片描述

step1:C:\Users\wangrusheng\RiderProjects\WinFormsApp18\WinFormsApp18\Form1.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WinFormsApp18
{public partial class Form1 : Form{// 固定PDF路径配置 C:\Users\wangrusheng\Documentspublic const string FixedPdfPath = @"C:\Users\wangrusheng\Documents\age.pdf";private string _currentTempDir;// UI控件private TextBox txtSaveDir;private NumericUpDown numStartPage;private NumericUpDown numEndPage;private ComboBox cmbQuality;private CheckBox chkMerge;private ComboBox cmbOrientation;public Form1(){InitializeComponent();InitializeComponents();LoadSettings();}private void InitializeComponents(){// 固定PDF路径显示var lblFile = new Label{Text = "PDF文件路径:",Location = new Point(20, 20),AutoSize = true};var txtFixedPath = new TextBox{Text = FixedPdfPath,Location = new Point(120, 17),Width = 400,ReadOnly = true,BackColor = SystemColors.Window};// 保存目录区域var lblSaveDir = new Label{Text = "保存目录:",Location = new Point(20, 60),AutoSize = true};txtSaveDir = new TextBox{Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),"PdfToJpgOutput"),Location = new Point(120, 57),Width = 400,ReadOnly = true};var btnSelectDir = new Button{Text = "浏览...",Location = new Point(530, 55),AutoSize = true};btnSelectDir.Click += BtnSelectDir_Click;// 页码选择var lblPages = new Label{Text = "页码范围:",Location = new Point(20, 100),AutoSize = true};numStartPage = new NumericUpDown{Location = new Point(120, 97),Minimum = 1,Maximum = 10000};numEndPage = new NumericUpDown{Location = new Point(220, 97),Minimum = 0,Maximum = 10000};// 质量选择var lblQuality = new Label{Text = "输出质量:",Location = new Point(20, 140),AutoSize = true};cmbQuality = new ComboBox{Location = new Point(120, 137),Items = { "300", "400", "500", "600" },SelectedIndex = 2};// 合并选项chkMerge = new CheckBox{Text = "合并为单文件",Location = new Point(20, 180),AutoSize = true};cmbOrientation = new ComboBox{Location = new Point(120, 177),Items = { "垂直拼接", "水平拼接" },SelectedIndex = 0};// 操作按钮var btnRun = new Button{Text = "开始转换",Location = new Point(20, 220),AutoSize = true};btnRun.Click += BtnRun_Click;// 添加所有控件Controls.AddRange(new Control[]{lblFile, txtFixedPath,lblSaveDir, txtSaveDir, btnSelectDir,lblPages, numStartPage, numEndPage,lblQuality, cmbQuality,chkMerge, cmbOrientation,btnRun});}private void BtnSelectDir_Click(object sender, EventArgs e){using var dialog = new FolderBrowserDialog{SelectedPath = txtSaveDir.Text,Description = "选择保存目录"};if (dialog.ShowDialog() == DialogResult.OK){if (FileHelper.ValidatePath(dialog.SelectedPath)){txtSaveDir.Text = dialog.SelectedPath;}else{MessageBox.Show("选择的目录路径无效");}}}private async void BtnRun_Click(object sender, EventArgs e){try{if (!ValidateInputs()) return;_currentTempDir = FileHelper.GetTempWorkspace();var result = await ConvertPdfToImagesAsync();if (result.Success){if (chkMerge.Checked){await MergeImagesAsync();}MoveFinalFiles();MessageBox.Show("转换成功完成");}else{throw new Exception(result.ErrorMessage);}}catch (Exception ex){MessageBox.Show($"操作失败: {ex.Message}");}finally{FileHelper.CleanTempFiles(_currentTempDir);}}private bool ValidateInputs(){if (!File.Exists(FixedPdfPath)){MessageBox.Show($"自动读取的PDF文件不存在:{FixedPdfPath}");return false;}if (numStartPage.Value > numEndPage.Value && numEndPage.Value != 0){MessageBox.Show("起始页码不能大于结束页码");return false;}return true;}private async Task<(bool Success, string ErrorMessage)> ConvertPdfToImagesAsync(){var args = new List<string>{"-dNOSAFER",$"-r{cmbQuality.SelectedItem}","-sDEVICE=jpeg","-dBATCH","-dNOPAUSE","-dEPSCrop",$"-dFirstPage={numStartPage.Value}",numEndPage.Value > 0 ? $"-dLastPage={numEndPage.Value}" : "",$"-sOutputFile={Path.Combine(_currentTempDir, "page_%d.jpg")}",$"\"{FixedPdfPath}\""};var (success, output) = FileHelper.ExecuteCommand("gswin64c", string.Join(" ", args), _currentTempDir);return (success, output);}private async Task MergeImagesAsync(){var args = $"{Path.Combine(_currentTempDir, "page_*.jpg")} " +$"{(cmbOrientation.SelectedIndex == 0 ? "-append" : "+append")} " +$"{Path.Combine(_currentTempDir, "merged.jpg")}";var (success, output) = FileHelper.ExecuteCommand("magick", args, _currentTempDir);if (!success) throw new Exception(output);}private void MoveFinalFiles(){var destDir = txtSaveDir.Text;Directory.CreateDirectory(destDir);var filesToMove = chkMerge.Checked? new[] { "merged.jpg" }: Directory.GetFiles(_currentTempDir, "page_*.jpg");foreach (var file in filesToMove){var destPath = Path.Combine(destDir, Path.GetFileName(file));File.Move(file, destPath, true);}}private void LoadSettings(){// 可添加其他配置加载逻辑numStartPage.Value = 1;numEndPage.Value = 0;}private void SaveSettings(){// 可添加配置保存逻辑}protected override void OnFormClosing(FormClosingEventArgs e){SaveSettings();base.OnFormClosing(e);}}
}

step2:C:\Users\wangrusheng\RiderProjects\WinFormsApp18\WinFormsApp18\FileHelper.cs

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;namespace WinFormsApp18
{public static class FileHelper{private const string GhostscriptExeName = "gswin64c.exe";private static readonly string[] GhostscriptSearchPaths = {@"D:\Program Files\gs"};public static string GetTempWorkspace(){var tempDir = Path.Combine(Path.GetTempPath(),"PdfToJpg",DateTime.Now.ToString("yyyyMMdd_HHmmss"));Directory.CreateDirectory(tempDir);return tempDir;}public static bool ValidatePath(string path){try{var fullPath = Path.GetFullPath(path);if (path.IndexOfAny(Path.GetInvalidPathChars()) >= 0)return false;if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)){if (!fullPath.StartsWith(ApplicationInfo.AppRootPath, StringComparison.OrdinalIgnoreCase))return false;}else{if (!fullPath.StartsWith(ApplicationInfo.AppRootPath))return false;}return true;}catch{return false;}}public static (bool Success, string Output) ExecuteCommand(string command, string args, string workingDir){try{var fullCommandPath = command.Equals("gswin64c", StringComparison.OrdinalIgnoreCase)? FindGhostscriptPath(): command;if (fullCommandPath == null)throw new FileNotFoundException("Ghostscript not found. Please install from https://www.ghostscript.com/");var startInfo = new ProcessStartInfo{FileName = fullCommandPath,Arguments = args,WorkingDirectory = workingDir,UseShellExecute = false,RedirectStandardOutput = true,RedirectStandardError = true,CreateNoWindow = true};using var process = Process.Start(startInfo);var output = process.StandardOutput.ReadToEnd();var error = process.StandardError.ReadToEnd();if (!process.WaitForExit(30000))throw new TimeoutException("Process execution timed out");return (process.ExitCode == 0, $"Exit Code: {process.ExitCode}\nOutput:\n{output}\nErrors:\n{error}");}catch (Exception ex){return (false, ex.Message);}}private static string FindGhostscriptPath(){// Check if ghostscript is in PATHvar pathEnv = Environment.GetEnvironmentVariable("PATH") ?? "";foreach (var path in pathEnv.Split(Path.PathSeparator)){var fullPath = Path.Combine(path, GhostscriptExeName);if (File.Exists(fullPath))return fullPath;}// Search common installation directoriesforeach (var basePath in GhostscriptSearchPaths){if (!Directory.Exists(basePath)) continue;var versions = Directory.GetDirectories(basePath).OrderByDescending(d => d).ToList();foreach (var versionDir in versions){var exePath = Path.Combine(versionDir, "bin", GhostscriptExeName);if (File.Exists(exePath))return exePath;}}throw new FileNotFoundException($"Ghostscript executable ({GhostscriptExeName}) not found. " +"Please install from https://www.ghostscript.com/");}public static void CleanTempFiles(string tempDir){try{if (Directory.Exists(tempDir)){Directory.Delete(tempDir, true);}}catch (Exception ex){Debug.WriteLine($"Error cleaning temp files: {ex.Message}");}}}public static class ApplicationInfo{public static string AppRootPath => AppDomain.CurrentDomain.BaseDirectory;}
}

end

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75799.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring 核心技术解析【纯干货版】- XVIII:Spring 网络模块 Spring-WebSocket 模块精讲

在现代 Web 开发中&#xff0c;实时通信已成为提升用户体验的关键技术之一。传统的 HTTP 轮询方式存在较高的延迟和带宽开销&#xff0c;而 WebSocket 作为一种全双工通信协议&#xff0c;能够在客户端和服务器之间建立持久连接&#xff0c;实现高效的双向数据传输。 Spring 框…

VirtualBox安装FnOS

1.下载FnOS镜像 下载网址&#xff1a; https://www.fnnas.com/2.创建虚拟机 虚拟机配置如图所示&#xff08;注意操作系统类型和网卡配置&#xff09; &#xff08;注意启动顺序&#xff09; 3.启动虚拟机 网卡类型选择桥接的Virtual Adapter 如果没有IP地址或者IP地址无法…

java根据集合中对象的属性值大小生成排名

1&#xff1a;根据对象属性降序排列 public static <T extends Comparable<? super T>> LinkedHashMap<T, Integer> calculateRanking(List<ProductPerformanceInfoVO> dataList, Function<ProductPerformanceInfoVO, T> keyExtractor) {Linked…

grep命令: 过滤

[rootxxx ~]# grep root /etc/passwd [rootxxx ~]# grep -A 2 root /etc/passwd -A #匹配行后两行 [rootxxx ~]# grep -B 2 root /etc/passwd -B #匹配行前两行 [rootxxx ~]# grep -C 2 root /etc/passwd -C #前后2行 [rootxxx ~]# grep -n root /…

二十种中药果实识别分类系统,Python/resnet18/pytorch

二十种中药果实识别分类系统,Python/resnet18/pytorch 基于pytorch训练, resnet18网络&#xff0c;可用于训练其他分类问题&#xff0c;也可自己重新训练 20类中药材具体包括&#xff1a;(1) 补骨脂&#xff0c;(2) 草豆蔻&#xff0c;(3) 川楝子&#xff0c;(4) 地肤子&…

SpringBoot启动run方法分析

SpringBoot启动run方法分析 1.场景引入 在项目启动的时候&#xff0c;有时候我们需要在启动的时候&#xff0c;执行一些逻辑。 比如说&#xff0c;项目启动的时候&#xff0c;我想把一些热门商品的数据加载到缓存中去&#xff1b; 比如说&#xff0c;自定义了一个netty服务…

Linux信号——信号的处理(3)

信号是什么时候被处理&#xff1f; 进程从内核态&#xff0c;切换到用户态的时候&#xff0c;信号会被检测处理。 内核态&#xff1a;操作系统的状态&#xff0c;权限级别高 用户态&#xff1a;你自己的状态 内核态和用户态 进程地址空间第三次 所谓的系统调用本质其实是一堆…

MySQL篇(四)事务相关知识详解

MySQL篇(四&#xff09;事务相关知识详解 MySQL篇(四&#xff09;事务相关知识详解一、事务的特性&#xff08;ACID&#xff09;原子性&#xff08;Atomicity&#xff09;一致性&#xff08;Consistency&#xff09;隔离性&#xff08;Isolation&#xff09;持久性&#xff08;…

SpringBoot定时任务深度优化指南

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 SpringBoot定时任务深度优化指南 引言 在分布式系统架构中&#xff0c;定时任务是实现业务逻辑自动化的重要组件。SpringBoot通过Scheduled注解提供了便捷的…

MySQL表结构导出(Excel)

目录 一、java实现MySQL表结构导出&#xff08;Excel&#xff09; 二、python实现MySQL表结构导出&#xff08;Excel&#xff09; 又到了写毕设的时候了&#xff0c;计算机专业在写论文第四章系统设计的时候肯定会遇到和我一样的难题——要在论文中将数据库的表结构以表格形式…

Android使用OpenGL和MediaCodec渲染视频

目录 一&#xff0c;借助MediaCodec封装解码工具类VideoCodec 二&#xff0c;使用OpenGl绘制视频封装SoulFilter 一&#xff0c;借助MediaCodec封装解码工具类VideoCodec /*** 解码工具类* 解码完成后的数据 通过 ISurface 回调出去*/ public class VideoCodec {private ISu…

day39——输入操作:多值输入

数组输入&#xff1a; int main() {//***** 1、多值输入&#xff08;C&#xff09;/*输入&#xff1a;3 --> 3个值5 4 9*/int n;cin >> n; //输入个数const int MAX_SIZE 0xFFFF;//限定最大个数int a[MAX_SIZE];for (int i 0; i < n; i) {//用 n 作控制输入…

第九课:LoRA模型的原理及应用

文章目录 Part.01 3种LoRA的使用方式Part.02 5种LoRA的应用方向Part.01 3种LoRA的使用方式 LoRA能够在家用级设备上训练,实现对Checkpoint在某些方面的微调使用Lora的三种方式:放置Lora模型到目录中,然后作为提示词的一部分输入。点击生成按钮下面的“画”,然后打开Additio…

Cortex-M3 NVIC可以控制异常向量表的哪些部分

Cortex-M3 的 NVIC(嵌套向量中断控制器)不直接控制整个异常向量表,但可以管理向量表中与中断相关的部分行为。以下是 NVIC 对异常向量表的具体控制范围和相关机制: 1. NVIC 直接控制的部分 NVIC 主要管理 外部中断(IRQ) 和部分 系统异常 的行为,但对向量表本身的存储位…

双向链表增删改查的模拟实现

本章目标 0.双向链表的基本结构 1.双向链表的初始化 2.头插尾插 3.头删尾删 4.查找与打印 5.在指定位置之前插入数据/在指定位置之后插入数据 6.在指定位置之前删除数据/在指定位置之后删除数据 7.销毁链表 0.双向链表的基本结构 本章所实现的双向链表是双向循环带头链表,是…

实战交易策略 篇十四:江南神鹰捕捉热点和熊市生存交易策略

文章目录 系列文章捕捉热点是股市最大的掘金术市场温度不低于50是热点产生的必要条件题材的大小和新颖程度决定热点的持续时间和涨幅炒作热点的3个阶段捕捉热点的方法与步骤操作实战案例熊市生存术“熊市最好的做法是离开股市”的说法是一句空话熊市盈利模式:不轻言底部,超跌…

Linux错误(6)X64向量指令访问地址未对齐引起SIGSEGV

Linux错误(6)X64向量指令访问地址未对齐引起SIGSEGV Author: Once Day Date: 2025年4月4日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: Linux实…

解码 __iter__ 和 itertools.islice - 迭代的艺术

文章目录 前言一、`_iter__`:自定义迭代的钥匙1.1 什么是 __iter__?1.2 基本用法1.3 高级用法:独立迭代器二、itertools.islice:迭代切片的利器2.1 什么是 itertools.islice?2.2 基本用法2.3 处理无限序列2.4 实际应用三、`__iter__` 与 `islice` 的结合六、为什么需要它们…

使用VSCode编写C#程序

目录 一、环境搭建&#xff1a;构建高效开发基础1. 安装VSCode2. 配置.NET SDK3. 安装核心扩展 二、项目开发全流程1. 创建项目2. 代码编辑技巧3. 调试配置4. 高级调试技巧5. 编译与运行 三、常见问题解决指南1. 项目加载失败2. IntelliSense失效3. 代码格式化4. 典型编译错误&…

日本汽车规模性经济计划失败,日产三大品牌的合并合作共赢,还是绝地求生?本田与日产合并确认失败,将成为世界第三大汽车集团愿景失败

本田与日产(含三菱汽车)的合并计划最终因核心矛盾无法调和而宣告失败,这一事件揭示了传统车企在行业变革期的深层困境。以下从合并动机、失败原因、本质判断及未来影响等方面综合分析: 一、合并的初衷:生存压力主导的被动策略 市场危机与财务困境 中国市场溃败:日系品牌在…