找回密码
 立即注册
首页 业界区 业界 WinForms中实现Adobe PDF Reader实现旋转PDF功能 ...

WinForms中实现Adobe PDF Reader实现旋转PDF功能

施婉秀 2025-6-11 10:40:30
实现效果:

1.gif

问题点: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并保存替换当前的文件。
  1.                  /// <summary>
  2.         /// 旋转保存PDF文件并释放文件锁定
  3.         /// </summary>
  4.         /// <param name="axControl"></param>
  5.         /// <param name="filePath"></param>
  6.         /// <param name="pdfRotation"></param>
  7.         /// <returns></returns>   
  8. public bool SafeSavePdfWithRelease(AxAcroPDFLib.AxAcroPDF axControl, string filePath, PdfRotation pdfRotation)
  9.     {
  10.         const int MAX_RETRY = 3;
  11.         const int RETRY_DELAY = 500;
  12.         for (int attempt = 0; attempt < MAX_RETRY; attempt++)
  13.         {
  14.             try
  15.             {
  16.                 // 步骤1:创建临时副本
  17.                 string tempPath = Path.GetTempFileName().Replace(".tmp", ".pdf");
  18.                 File.Copy(filePath, tempPath, true);
  19.                 // 步骤2:使用内存流操作
  20.                 using (var ms = new MemoryStream(File.ReadAllBytes(tempPath)))
  21.                 using (var document = PdfiumViewer.PdfDocument.Load(ms))
  22.                 {
  23.                     for (int pageIndex = 0; pageIndex < document.PageCount; pageIndex++)
  24.                     {
  25.                         document.RotatePage(pageIndex, pdfRotation);
  26.                         // 可选:验证旋转结果
  27.                         // var currentRotation = document.Pages[pageIndex].Rotation;
  28.                         // Debug.Assert(currentRotation == (int)rotation);
  29.                     }
  30.                     // 执行修改操作(示例:旋转第一页)
  31.                     //document.RotatePage(1, PdfRotation.Rotate90);
  32.                     // 步骤3:保存到临时文件
  33.                     byte[] pdfBytes;
  34.                     using (var outputStream = new MemoryStream())
  35.                     {
  36.                         document.Save(outputStream);
  37.                         pdfBytes = outputStream.ToArray();
  38.                     }
  39.                     // 步骤4:强制释放文件锁定
  40.                     ForceReleasePdfFile(axControl, filePath);
  41.                     // 步骤5:原子替换文件
  42.                     File.WriteAllBytes(tempPath, pdfBytes);
  43.                     // File.Replace(tempPath, filePath, null, true);
  44.                     // 1. 复制替换文件到目标路径
  45.                     File.Copy(tempPath, filePath, overwrite: true);
  46.                     // 2. 删除临时文件(可选)
  47.                     File.Delete(tempPath);
  48.                     // 步骤6:验证加载
  49.                     axControl.LoadFile(filePath);
  50.                     return true;
  51.                 }
  52.             }
  53.             catch (IOException ex) when (ex.HResult == -2147024864)
  54.             {
  55.                 if (attempt == MAX_RETRY - 1) throw;
  56.                 Thread.Sleep(RETRY_DELAY);
  57.             }
  58.         }
  59.         return false;
  60.     }
  61.     public void ForceReleasePdfFile(AxAcroPDFLib.AxAcroPDF axControl, string filePath)
  62.     {
  63.         // 步骤1:深度释放COM对象
  64.         ReleaseComObject(axControl);
  65.         // 步骤2:内核级文件解锁
  66.         UnlockFileHandle(filePath);
  67.         // 步骤3:延迟重载验证
  68.         Thread.Sleep(200);
  69.         axControl.LoadFile(filePath);
  70.     }
  71.     private void ReleaseComObject(AxAcroPDFLib.AxAcroPDF axControl)
  72.     {
  73.         try
  74.         {
  75.             // 显式释放ActiveX资源
  76.             if (axControl.IsDisposed) return;
  77.             // 反射调用内部释放方法
  78.             var type = axControl.GetType();
  79.             var method = type.GetMethod("ReleaseOCX", BindingFlags.Instance | BindingFlags.NonPublic);
  80.             method?.Invoke(axControl, null);
  81.             // 强制垃圾回收
  82.             GC.Collect();
  83.             GC.WaitForPendingFinalizers();
  84.         }
  85.         catch (Exception ex)
  86.         {
  87.         }
  88.     }
  89.     // 修改后的P/Invoke声明
  90.     [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  91.     private static extern IntPtr CreateFile(
  92.         string lpFileName,
  93.         uint dwDesiredAccess,
  94.         uint dwShareMode,
  95.         IntPtr lpSecurityAttributes,
  96.         FileMode dwCreationDisposition,  // 改用.NET枚举
  97.         FileAttributes dwFlagsAndAttributes,  // 改用.NET枚举
  98.         IntPtr hTemplateFile);
  99.     // 修改后的UnlockFileHandle方法
  100.     private void UnlockFileHandle(string filePath)
  101.     {
  102.         const uint FILE_SHARE_READ = 0x00000001;
  103.         const uint FILE_SHARE_WRITE = 0x00000002;
  104.         const uint GENERIC_READ = 0x80000000;
  105.         IntPtr hFile = CreateFile(
  106.             filePath,
  107.             GENERIC_READ,
  108.             FILE_SHARE_READ | FILE_SHARE_WRITE,
  109.             IntPtr.Zero,
  110.             FileMode.Open,  // 对应原生OPEN_EXISTING
  111.             FileAttributes.Normal,  // 对应原生FILE_ATTRIBUTE_NORMAL
  112.             IntPtr.Zero);
  113.         if (hFile != IntPtr.Zero && hFile != new IntPtr(-1))
  114.         {
  115.             CloseHandle(hFile);
  116.         }
  117.     }
  118.     [DllImport("kernel32.dll", SetLastError = true)]
  119.     [return: MarshalAs(UnmanagedType.Bool)]
  120.     private static extern bool CloseHandle(IntPtr hObject);`
复制代码
调用代码:
[code]                  ///         /// 当前旋转角度        ///         public static int currentRotation = 0;        ///         /// 逆时针旋转        ///         ///         ///         private void pictureEdit3_Click(object sender, EventArgs e)        {            if (axAcroPDF1.Visible)            {                currentRotation -= 90;                 PdfRotation pdfRotation = GetCounterClockwiseRotation(currentRotation);                                 var path = axAcroPDF1.src;                //调用旋转PDF保存方法                SafeSavePdfWithRelease(axAcroPDF1, path,pdfRotation);                 axAcroPDF1.LoadFile(path);                axAcroPDF1.setView("Fit"); //适应窗口大小            }        }        ///         /// 顺时针旋转        ///         ///         ///         private void pictureEdit2_Click(object sender, EventArgs e)        {            if (axAcroPDF1.Visible)            {                currentRotation += 90;                 PdfRotation pdfRotation = GetCounterClockwiseRotation(currentRotation);                var path = axAcroPDF1.src;                //调用旋转PDF保存方法                SafeSavePdfWithRelease(axAcroPDF1, path, pdfRotation);                axAcroPDF1.LoadFile(path);                axAcroPDF1.setView("Fit"); //适应窗口大小             }        }        ///         /// 通过旋转度数计算旋转的角度        ///         /// 当前旋转角度        public static PdfRotation GetCounterClockwiseRotation(int counterClockwiseDegrees)        {            const int fullCircle = 360;            int effectiveDegrees = counterClockwiseDegrees % fullCircle;            if (effectiveDegrees < 0) effectiveDegrees += fullCircle; // 处理负角度            if (currentRotation >= 360)             {                currentRotation = 0;            }            if (currentRotation
您需要登录后才可以回帖 登录 | 立即注册