实现效果:
问题点: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>