Unity-PDF分割器(iTextSharp)

news2024/11/18 0:44:48

PDF分割器

  • Unity-PDF分割器
    • 前言
    • 核心思路
    • 解决过程
      • 一、Unity安装iTextSharp
      • 二、运行时计算将要生成文件的大小
      • 三、分割核心代码
      • 四、使用StandaloneFileBrowser
      • 五、其他的一些脚本
      • 六、游戏界面主体的构建
        • MainWindow
        • WarningPanel & FinishPanel
  • By-Round Moon

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;
    }

三、分割核心代码

这份脚本为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();
    }
}

四、使用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;
    }

}

五、其他的一些脚本

这份脚本为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();
    }
}

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

using UnityEngine;

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

六、游戏界面主体的构建

MainWindow

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

WarningPanel & FinishPanel

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

By-Round Moon

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

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

相关文章

Vue3 在SCSS中使用v-bind

template 先创建一个通用的页面结构 <template><div class"v-bubble-bg"></div> </template>js 在JS中先对需要用的数据进行定义&#xff1a; 可以是参数&#xff0c;也可以是data <script setup>const props defineProps({bgCol…

Linux零基础快速入门

Linux的诞生 Linux创始人:林纳斯 托瓦兹 Linux 诞生于1991年&#xff0c;作者上大学期间 因为创始人在上大学期间经常需要浏览新闻和处理邮件&#xff0c;发现现有的操作系统不好用,于是他决心自己写一个保护模式下的操作系统&#xff0c;这就是Linux的原型&#xff0c;当时他…

【笔记】:更方便的将一个List中的数据传入另一个List中,避免多重循环

这里是 simpleInfoList 集合&#xff0c;记为集合A&#xff08;传值对象&#xff09; List<CourseSimpleInfoDTO> simpleInfoList courseClient.getSimpleInfoList(courseIds);if(simpleInfoListnull){throw new BizIllegalException("当前课程不存在!");}这…

[Flutter]TextButton自定义样式

在Flutter中&#xff0c;TextButton是一个简单的文本按钮&#xff0c;它遵循当前的Theme。如果你想要修改TextButton的样式&#xff0c;可以通过设置其style属性来实现&#xff0c;该属性接收一个ButtonStyle对象。 给TextButton和里面Text添加背景后&#xff0c;效果如下。可…

设计模式(二)单例模式

单例模式&#xff1a;确保一个类只有一个实例&#xff0c;并提供了全局访问点&#xff1b;主要是用于控制共享资源的访问&#xff1b; 单例模式的实现分为懒汉式和饿汉式。 懒汉式单例在需要时才会创建&#xff0c;而饿汉式单例则在类加载时立即创建实例&#xff1b; 单例模…

【精准获客,优化体验】Xinstall助力企业提升App渠道效果与用户满意度

在数字化时代&#xff0c;企业对于用户体验的重视程度日益提升。为了更好地满足用户需求&#xff0c;提供个性化、专属化的服务已经成为企业竞争的关键。今天&#xff0c;我们将向大家介绍一款名为Xinstall的一站式App全渠道统计服务商&#xff0c;它凭借强大的技术实力和丰富的…

【测试开发面试复习(一)】计算机网络:计算机网络体系结构(P1)补充ing

我每次复习的第一趴都是网络。。 一、高频面试题记录 1.1 计算机网络为什么要分层&#xff1f; 网络庞大而且复杂&#xff08;大量的软硬件系统、大量的程序和协议等&#xff09;&#xff0c;分层可提高整体结构的灵活性、将层次之间结构解耦&#xff0c;各层相互独立、隔离&…

轻松三步制作电子签名

一、在纸上签名&#xff0c;并且拍照。 二、新建空白word文档&#xff0c;使用WPS方式打开&#xff0c;再将图片复制进来。 三、点击图片&#xff0c;先选择【图片工具】中的【设置透明色】&#xff0c;然后点击签名之外的图片背景&#xff0c;即可制作为矢量图&#xff1b…

Redis 面试指南:常见问题及最佳答案

Redis 是一个高性能的键值存储系统&#xff0c;已经成为了许多企业和互联网公司的核心技术之一。本文将总结 Redis 面试中常见的问题&#xff0c;并提供最佳答案&#xff0c;以帮助读者更好地准备 Redis 面试。 引言&#xff1a; Redis 是一个开源、高性能、键值存储系统&…

朴素贝叶斯(带你从原理到实践)

目录 一、引言 二、朴素贝叶斯算法原理 1 贝叶斯定理 2 特征条件独立假设 3 分类过程 三、实践事例 四、朴素贝叶斯算法应用 1 文本分类 2 垃圾邮件过滤 3 情感分析 五、朴素贝叶斯算法未来发展 1 特征选择优化 2 半监督学习与无监督学习 3 结合深度学习 4 处理…

vue中动态引入图片

分析 很多时间&#xff0c;不管是vue2&#xff0c;还是vue3开发中都会遇到&#xff0c;动态渲染图片的功能&#xff0c;但是为什么我们直接将图片的路径直接赋值给变量的时候&#xff0c;图片渲染不出来&#xff0c;而通过require引入加载图片后却能正常渲染呢&#xff1f;主要…

数仓开发环境链接

这里写目录标题 1开发工具链接大数据组件1.1 启动hiveserver21.2配置DataGrip连接1.3测试使用 2 环境问题排查思路 1开发工具链接大数据组件 1.1 启动hiveserver2 数仓开发工具datagrip 需要用到JDBC协议链接到Hive&#xff0c;需要启动hiveserver2。 cd /opt/module/hive h…

PHP项目中composer和Git的组合使用

highlight: 在国内由于众所周知的原因&#xff0c;composer的package可能无法访问&#xff0c;解决办法是使用中国的全镜像&#xff1a; composer config -g repositories.packagist composer http://packagist.phpcomposer.com 在需要使用composer package的地方创建composer…

算法沉淀——动态规划之两个数组的 dp(上)(leetcode真题剖析)

算法沉淀——动态规划之两个数组的 dp 01.最长公共子序列02.不相交的线03.不同的子序列04.通配符匹配 01.最长公共子序列 题目链接&#xff1a;https://leetcode.cn/problems/longest-common-subsequence/ 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 …

ADS-B Ground Receiver Radarcape

目录 Radarcape ADS-B MLAT Receiver Web Browser User Interface Radarcape Technical Data Radarcape Software Features Radarcape Basics Radarcape ADS-B MLAT Receiver Radarcape is a professional ADS-B receiver made for 24/7 operation. High performance rec…

2.29作业

T课上实现通信代码总结&#xff1a; 程序代码&#xff1a; TCPSER.c #include<myhead.h> #define SER_IP "192.168.244.140" //服务器IP #define SER_PORT 9999 //服务器端口号 int main(int argc, const char *argv[]) {//1.创建用于监…

踩坑之MysqlClient 安装

本以为就简单的 pip 就安装上了结果 报错 error: Microsoft Visual C 14.0 or greater is required. Get it with "Microsoft C Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/ 报错这个 让我下载 我也下载了可能没重启问题 再次安装还…

JS api基础初学

轮播图随机版 需求&#xff1a;当我们刷新页面&#xff0c;页面中的轮播图会显示不同图片以及样式 分析&#xff1a;①&#xff1a;准备一个数组对象&#xff0c;里面包含详细信息&#xff08;素材包含&#xff09; ②&#xff1a;随机选择一个数字&#xff0c;选出数组对应…

layui中,父页面与子页面,函数方法的相互调用、传参

<%--父页面--%> <script type"text/javascript">var KaoHaoType 0; // 考号类型 自定义参数1// 选取考号类型function SelectKaoHaoType(callBack) {KaoHaoType 0; // 默认选择填涂考号layer.open({type: 2, title: 请选择 考号区类型, ar…

java BIO深入学习

一、BIO的工作原理 传统Io(BIO)的本质就是面向字节流来进行数据传输的 ①:当两个进程之间进行相互通信&#xff0c;我们需要建立一个用于传输数据的管道(输入流、输出流)&#xff0c;原来我们传输数据面对的直接就是管道里面一个个字节数据的流动&#xff08;我们弄了一个 by…