WinForm中实现Adobe PDF Reader实现旋转PDF功能
实现效果:
问题点:Adobe PDF Reader中并没有可以直接旋转的方法
LoadFile | 加载文件,文件URL地址 |
---|---|
GotoFirstPage | 到第一页 |
GotoLastPage | 到最后一页 |
GotoPreviousPage | 上一页 |
GotoNextPape | 下一页 |
SetCurrentpage | 到指定页 |
Setshowscrollbars | 设置是否显示 Acrobat Reader的滚动条。带一个参数,该参数设为0时不显示滚动条,设为1时显示滚动条 |
SetshowToolbar | 设置是否显示 Acrobat Reader的工具栏。带一个参数,该参数设为时不显示,设为1时显示。 |
Setview | 设置显示效果。Fit:适应窗口大小; FitH:适合宽度 |
setZoom | 设置文件的显示比例;默认是100 |
解决办法:引入PdfiumViewer旋转PDF并保存替换当前的文件。
<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-c language-c#"> <span style="color:#008000">/// <summary></span><span style="color:#008000">/// 旋转保存PDF文件并释放文件锁定</span><span style="color:#008000">/// </summary></span><span style="color:#008000">/// <param name="axControl"></param></span><span style="color:#008000">/// <param name="filePath"></param></span><span style="color:#008000">/// <param name="pdfRotation"></param></span><span style="color:#008000">/// <returns></returns> </span>
public <span style="color:#a31515">bool</span> <span style="color:#a31515">SafeSavePdfWithRelease</span>(AxAcroPDFLib.AxAcroPDF axControl, <span style="color:#0000ff">string</span> filePath, PdfRotation pdfRotation){<span style="color:#a31515">const</span> <span style="color:#a31515">int</span> MAX_RETRY = <span style="color:#880000">3</span>;<span style="color:#a31515">const</span> <span style="color:#a31515">int</span> RETRY_DELAY = <span style="color:#880000">500</span>;<span style="color:#0000ff">for</span> (<span style="color:#a31515">int</span> attempt = <span style="color:#880000">0</span>; attempt < MAX_RETRY; attempt++){try{<span style="color:#008000">// 步骤1:创建临时副本</span><span style="color:#0000ff">string</span> tempPath = Path.GetTempFileName().Replace(<span style="color:#a31515">".tmp"</span>, <span style="color:#a31515">".pdf"</span>);File.Copy(filePath, tempPath, <span style="color:#a31515">true</span>);<span style="color:#008000">// 步骤2:使用内存流操作</span>using (var ms = new MemoryStream(File.ReadAllBytes(tempPath)))using (var document = PdfiumViewer.PdfDocument.Load(ms)){<span style="color:#0000ff">for</span> (<span style="color:#a31515">int</span> pageIndex = <span style="color:#880000">0</span>; pageIndex < document.PageCount; pageIndex++){document.RotatePage(pageIndex, pdfRotation);<span style="color:#008000">// 可选:验证旋转结果</span><span style="color:#008000">// var currentRotation = document.Pages[pageIndex].Rotation;</span><span style="color:#008000">// Debug.Assert(currentRotation == (int)rotation);</span>}<span style="color:#008000">// 执行修改操作(示例:旋转第一页)</span><span style="color:#008000">//document.RotatePage(1, PdfRotation.Rotate90);</span><span style="color:#008000">// 步骤3:保存到临时文件</span>byte[] pdfBytes;using (var outputStream = new MemoryStream()){document.Save(outputStream);pdfBytes = outputStream.ToArray();}<span style="color:#008000">// 步骤4:强制释放文件锁定</span>ForceReleasePdfFile(axControl, filePath);<span style="color:#008000">// 步骤5:原子替换文件</span>File.WriteAllBytes(tempPath, pdfBytes);<span style="color:#008000">// File.Replace(tempPath, filePath, null, true);</span><span style="color:#008000">// 1. 复制替换文件到目标路径</span>File.Copy(tempPath, filePath, overwrite: <span style="color:#a31515">true</span>);<span style="color:#008000">// 2. 删除临时文件(可选)</span>File.Delete(tempPath);<span style="color:#008000">// 步骤6:验证加载</span>axControl.LoadFile(filePath);<span style="color:#0000ff">return</span> <span style="color:#a31515">true</span>;}}catch (IOException ex) when (ex.HResult == <span style="color:#880000">-2147024864</span>){<span style="color:#0000ff">if</span> (attempt == MAX_RETRY - <span style="color:#880000">1</span>) throw;Thread.Sleep(RETRY_DELAY);}}<span style="color:#0000ff">return</span> <span style="color:#a31515">false</span>;}public <span style="color:#a31515">void</span> <span style="color:#a31515">ForceReleasePdfFile</span>(AxAcroPDFLib.AxAcroPDF axControl, <span style="color:#0000ff">string</span> filePath){<span style="color:#008000">// 步骤1:深度释放COM对象</span>ReleaseComObject(axControl);<span style="color:#008000">// 步骤2:内核级文件解锁</span>UnlockFileHandle(filePath);<span style="color:#008000">// 步骤3:延迟重载验证</span>Thread.Sleep(<span style="color:#880000">200</span>);axControl.LoadFile(filePath);}private <span style="color:#a31515">void</span> <span style="color:#a31515">ReleaseComObject</span>(AxAcroPDFLib.AxAcroPDF axControl){try{<span style="color:#008000">// 显式释放ActiveX资源</span><span style="color:#0000ff">if</span> (axControl.IsDisposed) <span style="color:#0000ff">return</span>;<span style="color:#008000">// 反射调用内部释放方法</span>var type = axControl.GetType();var method = type.GetMethod(<span style="color:#a31515">"ReleaseOCX"</span>, BindingFlags.Instance | BindingFlags.NonPublic);method?.Invoke(axControl, null);<span style="color:#008000">// 强制垃圾回收</span>GC.Collect();GC.WaitForPendingFinalizers();}catch (Exception ex){}}<span style="color:#008000">// 修改后的P/Invoke声明</span>[DllImport(<span style="color:#a31515">"kernel32.dll"</span>, SetLastError = <span style="color:#a31515">true</span>, CharSet = CharSet.Auto)]private <span style="color:#a31515">static</span> <span style="color:#0000ff">extern</span> IntPtr <span style="color:#a31515">CreateFile</span>(<span style="color:#0000ff">string</span> lpFileName,uint dwDesiredAccess,uint dwShareMode,IntPtr lpSecurityAttributes,FileMode dwCreationDisposition, <span style="color:#008000">// 改用.NET枚举</span>FileAttributes dwFlagsAndAttributes, <span style="color:#008000">// 改用.NET枚举</span>IntPtr hTemplateFile);<span style="color:#008000">// 修改后的UnlockFileHandle方法</span>private <span style="color:#a31515">void</span> <span style="color:#a31515">UnlockFileHandle</span>(<span style="color:#0000ff">string</span> filePath){<span style="color:#a31515">const</span> uint FILE_SHARE_READ = <span style="color:#880000">0x00000001</span>;<span style="color:#a31515">const</span> uint FILE_SHARE_WRITE = <span style="color:#880000">0x00000002</span>;<span style="color:#a31515">const</span> uint GENERIC_READ = <span style="color:#880000">0x80000000</span>;IntPtr hFile = CreateFile(filePath,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,IntPtr.Zero,FileMode.Open, <span style="color:#008000">// 对应原生OPEN_EXISTING</span>FileAttributes.Normal, <span style="color:#008000">// 对应原生FILE_ATTRIBUTE_NORMAL</span>IntPtr.Zero);<span style="color:#0000ff">if</span> (hFile != IntPtr.Zero && hFile != new IntPtr(<span style="color:#880000">-1</span>)){CloseHandle(hFile);}}[DllImport(<span style="color:#a31515">"kernel32.dll"</span>, SetLastError = <span style="color:#a31515">true</span>)][<span style="color:#0000ff">return</span>: MarshalAs(UnmanagedType.Bool)]private <span style="color:#a31515">static</span> <span style="color:#0000ff">extern</span> <span style="color:#a31515">bool</span> CloseHandle(IntPtr hObject);`
</code></span></span>
调用代码:
<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-C language-C#"> <span style="color:#008000">/// <summary></span><span style="color:#008000">/// 当前旋转角度</span><span style="color:#008000">/// </summary></span>public <span style="color:#a31515">static</span> <span style="color:#a31515">int</span> currentRotation = <span style="color:#880000">0</span>;<span style="color:#008000">/// <summary></span><span style="color:#008000">/// 逆时针旋转</span><span style="color:#008000">/// </summary></span><span style="color:#008000">/// <param name="sender"></param></span><span style="color:#008000">/// <param name="e"></param></span>private <span style="color:#a31515">void</span> <span style="color:#a31515">pictureEdit3_Click</span>(object sender, EventArgs e){<span style="color:#0000ff">if</span> (axAcroPDF1.Visible){currentRotation -= <span style="color:#880000">90</span>; PdfRotation pdfRotation = GetCounterClockwiseRotation(currentRotation);var path = axAcroPDF1.src;<span style="color:#008000">//调用旋转PDF保存方法</span>SafeSavePdfWithRelease(axAcroPDF1, path,pdfRotation); axAcroPDF1.LoadFile(path);axAcroPDF1.setView(<span style="color:#a31515">"Fit"</span>); <span style="color:#008000">//适应窗口大小</span>}}<span style="color:#008000">/// <summary></span><span style="color:#008000">/// 顺时针旋转</span><span style="color:#008000">/// </summary></span><span style="color:#008000">/// <param name="sender"></param></span><span style="color:#008000">/// <param name="e"></param></span>private <span style="color:#a31515">void</span> <span style="color:#a31515">pictureEdit2_Click</span>(object sender, EventArgs e){<span style="color:#0000ff">if</span> (axAcroPDF1.Visible){currentRotation += <span style="color:#880000">90</span>; PdfRotation pdfRotation = GetCounterClockwiseRotation(currentRotation);var path = axAcroPDF1.src;<span style="color:#008000">//调用旋转PDF保存方法</span>SafeSavePdfWithRelease(axAcroPDF1, path, pdfRotation);axAcroPDF1.LoadFile(path);axAcroPDF1.setView(<span style="color:#a31515">"Fit"</span>); <span style="color:#008000">//适应窗口大小 </span>}}<span style="color:#008000">/// <summary></span><span style="color:#008000">/// 通过旋转度数计算旋转的角度</span><span style="color:#008000">/// </summary></span><span style="color:#008000">/// <param name="counterClockwiseDegrees">当前旋转角度</param></span>public <span style="color:#a31515">static</span> PdfRotation <span style="color:#a31515">GetCounterClockwiseRotation</span>(<span style="color:#a31515">int</span> counterClockwiseDegrees){<span style="color:#a31515">const</span> <span style="color:#a31515">int</span> fullCircle = <span style="color:#880000">360</span>;<span style="color:#a31515">int</span> effectiveDegrees = counterClockwiseDegrees % fullCircle;<span style="color:#0000ff">if</span> (effectiveDegrees < <span style="color:#880000">0</span>) effectiveDegrees += fullCircle; <span style="color:#008000">// 处理负角度</span><span style="color:#0000ff">if</span> (currentRotation >= <span style="color:#880000">360</span>) {currentRotation = <span style="color:#880000">0</span>;}<span style="color:#0000ff">if</span> (currentRotation <= <span style="color:#880000">-360</span>) {currentRotation = <span style="color:#880000">0</span>;}<span style="color:#0000ff">switch</span> (effectiveDegrees){<span style="color:#0000ff">case</span> <span style="color:#880000">90</span>:<span style="color:#0000ff">return</span> PdfRotation.Rotate90; <span style="color:#0000ff">case</span> <span style="color:#880000">180</span>:<span style="color:#0000ff">return</span> PdfRotation.Rotate180;<span style="color:#0000ff">case</span> <span style="color:#880000">270</span>:<span style="color:#0000ff">return</span> PdfRotation.Rotate270;<span style="color:#0000ff">case</span> <span style="color:#880000">0</span>:<span style="color:#0000ff">default</span>:<span style="color:#0000ff">return</span> PdfRotation.Rotate0;}}<span style="color:#008000">/// <summary></span>
</code></span></span>