当前位置:   article > 正文

Unity-PDF分割器(iTextSharp)

Unity-PDF分割器(iTextSharp)

Unity-PDF分割器

PDFSplitter 资源包下载链接【CSDN】免费

前言

最近有这么一个需求,PDF太大了,需要拆分成多份,要求每份的PDF不大于10MB。刚开始,我认为这应该很简单,但是足足耗费了一天的时间去解决该问题。

核心思路

首先是核心部分当然是PDF如何进行分割了,不仅仅要分割,还要统计分割的大小。然后我还不想伤硬盘,直接写在硬盘上判断文件是否超过了大小,然后回溯。所以我只能在运行的时候检测文件大小。核心部分的难度基本如上所述。下面来讲解一下我是如何解决这个问题的吧。还有一个最难的问题,那就是如何不用UnityEditor库来打开FilePanel又叫FileDialog

解决过程

一、Unity安装iTextSharp

在这里插入图片描述
    首先在Visual Studio Community中安装.NET 桌面开发,用来下载需要的dll。当然也可以直接在Unity中打开VS后下载,我这其实是脱裤子放屁,但是我想保持Unity的干净,不想事后卸载删除,所以我采用了这个方法。
    安装完成后创建一个控制台应用。在这里插入图片描述
将框架选为.NET Framework 2.0
打开后,在 工具》NuGet包管理器》管理解决方案的NuGet程序包。在浏览中搜索iTextSharp并安装。安装完成后,在.sln文件的同路径下有一个packages包,把里面BouncyCastle.1.8.9iTextSharp.5.5.13.3的lib文件夹下的.dll文件拷贝到Unity项目的Plugins(自己创建)文件夹中。
在这里插入图片描述

二、运行时计算将要生成文件的大小

    明确已知,没有提供方法来确定生成后的大小。但是我们可以先在MemoryStream中存储一下,并获取MemoryStream空间所消耗的大小。
    下面给出示例代码。

    long GetMemorySize(string inputFilePath)
    {
        PdfReader reader = new PdfReader(inputFilePath);
        Document document = new Document();
        MemoryStream memoryStream = new MemoryStream();
        PdfCopy copy = new PdfCopy(document, memoryStream);
        document.Open();
        copy.AddPage(copy.GetImportedPage(reader, 1));//这里页码是从1到最后的,不是常规的从0开始。
        long memorySize = memoryStream.Length;
        reader.Close();
        document.Close();
        memoryStream.Close();
        return memorySize;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

三、分割核心代码

这份脚本为PDFSplitter。将来挂在GameController空物体上。

using UnityEngine;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using UnityEngine.UI;
using System.Collections.Concurrent;
using System.Collections;

public class PDFSplitter : MonoBehaviour
{
    private string inputFilePath;
    private string outputDirectory;
    private long maxFileSizeMB = 10 * 1024 * 1024;
    private PdfReader reader;
    public InputField from;
    public InputField save;
    public Slider slider;
    private ConcurrentQueue<float> resultQueue = new ConcurrentQueue<float>();
    public void Splitter()
    {
        System.Threading.Thread thread = new System.Threading.Thread(Run);
        thread.Start();
        StartCoroutine(updateSlider());
    }
    IEnumerator updateSlider()
    {
        float res;
        while (true)
        {
            while (!resultQueue.TryDequeue(out res)) ;
            if (res < 0)
            {
                slider.value = 1.0f;
                GetComponent<GameController>().showFinishPanel = true;
                break;
            }
            slider.value = res;
            yield return null;
        }
    }
    public void Run()
    {
        int cnt = 1;
        int pre = 1;
        float rate;
        inputFilePath = from.text;
        outputDirectory = save.text;
        reader = new PdfReader(inputFilePath);
        PdfReader.unethicalreading = true;
        Document document = null;
        MemoryStream memoryStream = null;
        PdfCopy copy = null;
        int pageCount = reader.NumberOfPages;
        for (int i = 1; i <= pageCount; i++)
        {
            if (document == null)
            {
                document = new Document();
                memoryStream = new MemoryStream();
                copy = new PdfCopy(document, memoryStream);
                document.Open();
                copy.AddPage(copy.GetImportedPage(reader, i));
            }
            else
            {
                copy.AddPage(copy.GetImportedPage(reader, i));
                if (memoryStream.Length > maxFileSizeMB)
                {
                    PDF_Writer(pre, i - 1, cnt++.ToString("00"));
                    document.Close();
                    memoryStream.Close();
                    document = null;
                    memoryStream = null;
                    copy = null;
                    pre = i--;
                }
            }
            rate = 1.0f * i / pageCount;
            resultQueue.Enqueue(rate);
        }
        document.Close();
        PDF_Writer(pre, pageCount, cnt.ToString("00"));
        reader.Close();
        resultQueue.Enqueue(-1.0f);
    }
    void PDF_Writer(int start, int end, string name)
    {
        Document document = new Document();
        PdfCopy copy = new PdfCopy(document, new FileStream(outputDirectory + $"//{name}.pdf", FileMode.Create));
        document.Open();
        for (int i = start; i <= end; i++)
            copy.AddPage(copy.GetImportedPage(reader, i));
        document.Close();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

四、使用StandaloneFileBrowser

首先在Github链接中下载StandaloneFileBrowser。
在这里插入图片描述
之后,就将下载的Packages直接拖进项目中导入。
用这个包之后为了能够打包成功我们需要将Unity的.Net框架改为 .Net 4.x在这里插入图片描述
    我们这里只需要使用StandaloneFileBrowser.OpenFilePanelStandaloneFileBrowser.OpenFolderPanel
可能导入时候会出一些莫名其妙的错误,不用在意,只要能编译正常用,打包正常打出去,就可以。奇怪的是打包成功之后这些错误莫名其妙的消失掉了。


这份脚本为PathBar。将来挂在涉及路径选择的自定义物体上。

using UnityEngine;
using UnityEngine.UI;
using SFB;

public class PathBar : MonoBehaviour
{
    [HideInInspector]
    public string path;
    public InputField info;

    public void SelectFilePath()
    {
        var extensions = new[] { new ExtensionFilter("PDF Files", "pdf"), new ExtensionFilter("All Files", "*") };
        path = StandaloneFileBrowser.OpenFilePanel("Open PDF File", "", extensions, false)[0];
        info.text = path;
    }
    public void SelectFolderPath()
    {
        path = StandaloneFileBrowser.OpenFolderPanel("Select save Folder", "", false)[0];
        info.text = path;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

五、其他的一些脚本

这份脚本为GameController 。将来挂在GameController空物体上。

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
public class GameController : MonoBehaviour
{
    public GameObject FinishPanel;
    public GameObject WarningPanel;
    [HideInInspector]
    public bool showFinishPanel;
    public InputField from;
    public InputField save;
    public void Run()
    {
        if (!File.Exists(from.text) || !Directory.Exists(save.text) || Path.GetExtension(from.text).ToLower() != ".pdf")
        {
            WarningPanel.GetComponent<PanelController>().Open();
            return;
        }
        showFinishPanel = false;
        GetComponent<PDFSplitter>().Splitter();
        StartCoroutine(ShowFinishPanel());
    }
    IEnumerator ShowFinishPanel()
    {
        while (!showFinishPanel)
            yield return null;
        FinishPanel.GetComponent<PanelController>().Open();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

这份脚本为PanelController 。将来挂在一些用来提示的物体上。

using UnityEngine;

public class PanelController : MonoBehaviour
{
    public void Close()
    {
        gameObject.SetActive(false);
    }
    public void Open()
    {
        gameObject.SetActive(true);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

六、游戏界面主体的构建

MainWindow

在这里插入图片描述
界面如下,很好拆分上面的我称之为PathBar,用来选择路径。
中间是Button,用来执行分割操作。
最底下是进度条,可以参考B站视频 BV1iW411D78W大概在55分钟左右会有讲解。我这里多做了一步操作,把slider的图片全部设置成了None。
下面看一下我的目录结构
在这里插入图片描述

WarningPanel & FinishPanel

在这里插入图片描述
在这里插入图片描述
下面看一下我的目录结构
在这里插入图片描述
PDFSplitter 资源包下载链接【CSDN】免费

By-Round Moon

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号