unity 读取PPT显现到屏幕功能

news/2025/10/21 11:09:42/文章来源:https://www.cnblogs.com/wzzkaifa/p/19154544

1.准备一份PPT文件 和System.Drawing,Aspose.Slides这些dll文件,如图

2.unity默认设置,在Player下面找到api兼容级别 改成.NETFrameWork 如图

3.创建这些东西,并挂载脚本,脚本是其他大佬分享的,挺好使

4.运行即可 页数多的情况得另外搞

5.参考大佬的地址

⭐ Unity 异步加载PPT页面 并 首帧无卡顿显现_unity 加载ppt-CSDN博客

这个也能使用,有案例694fe · 万能工具箱/PPT加载插件v2.0Unity - GitCode

6.dll的话可以去上面工程找下,有报错也是dll的障碍和项目设置的问题

7.PPTCtrl脚本在这里

using Aspose.Slides;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;

public class PPTCtrl : MonoBehaviour
{
public UnityEngine.UI.Image ShowImg;//展示图片
public Text pagetext;//页数
public GameObject LastBtn, NextBtn;
public Sprite PlaceholderSprite; // 设置一个默认占位图 行用ppt第一张图

private Presentation presentation = null;
private int NowPage = 0;
private bool isLoading = false;

private Dictionary<int, Sprite> slideSprites = new Dictionary<int, Sprite>();

private async void Start()
{
UnityMainThreadDispatcher.Instance(); // 初始化主线程调度器

string PPTPath = Application.dataPath + "/Plugins/Aspose.Slides.NET.18.10.0(Crack)/165.pptx";
presentation = new Presentation(PPTPath);

// 用占位图先顶上 UI
ShowImg.sprite = PlaceholderSprite;

// 优先加载第一页
await LoadAndCacheSlideAsync(0);

// 延迟一帧再刷新 UI,避免卡顿
await Task.Delay(100);
SwitchPage(0);

// 后台加载其他页
_ = Task.Run(() => PreloadOtherSlidesAsync());
}

private void OnEnable()
{
LastBtn.GetComponent<Button>().onClick.AddListener(ClickLast);
NextBtn.GetComponent<Button>().onClick.AddListener(ClickNext);
}

private void OnDisable()
{
LastBtn.GetComponent<Button>().onClick.RemoveListener(ClickLast);
NextBtn.GetComponent<Button>().onClick.RemoveListener(ClickNext);
}


private async Task PreloadOtherSlidesAsync()
{
int total = presentation.Slides.Count;

for (int i = 1; i < total; i++)
{
if (!slideSprites.ContainsKey(i))
await LoadAndCacheSlideAsync(i);
}
}

private async Task LoadAndCacheSlideAsync(int page)
{
var slide = presentation.Slides[page];
var bitmap = slide.GetThumbnail(1f, 1f);
var bytes = GetBitMapBytes(bitmap);

await Task.Yield(); // 推出当前线程

UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
var tex = new Texture2D(bitmap.Width, bitmap.Height, TextureFormat.RGBA32, false);
tex.LoadImage(bytes);
var sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
slideSprites[page] = sprite;
});
}

public void SwitchPage(int page)
{
if (isLoading || page < 0 || page >= presentation.Slides.Count)
return;

NowPage = page;
pagetext.text = (page + 1) + " / " + presentation.Slides.Count;
LastBtn.SetActive(page > 0);
NextBtn.SetActive(page < presentation.Slides.Count - 1);

if (slideSprites.TryGetValue(page, out Sprite sprite))
{
ShowImg.sprite = sprite;
}
else
{
ShowImg.sprite = PlaceholderSprite;
StartCoroutine(LoadSlideAsync(page));
}
}

private IEnumerator LoadSlideAsync(int page)
{
isLoading = true;

yield return Task.Run(async () =>
{
await LoadAndCacheSlideAsync(page);
UnityMainThreadDispatcher.Instance().Enqueue(() =>
{
if (NowPage == page && slideSprites.ContainsKey(page))
{
ShowImg.sprite = slideSprites[page];
}
isLoading = false;
});
});
}

private byte[] GetBitMapBytes(Bitmap bm)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
bm.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
}
catch (Exception e)
{
Debug.LogWarning("Get Bytes failed: " + e);
return null;
}
}

public void ClickNext() => SwitchPage(NowPage + 1);
public void ClickLast() => SwitchPage(NowPage - 1);
}

8.主线程调度的脚本在这

using System;
using System.Collections.Generic;
using UnityEngine;

public class UnityMainThreadDispatcher : MonoBehaviour
{
private static readonly Queue<Action> _executionQueue = new Queue<Action>();
private static UnityMainThreadDispatcher _instance = null;

public static UnityMainThreadDispatcher Instance()
{
if (_instance == null)
{
var go = GameObject.Find("MainThreadDispatcher");
if (go == null)
{
go = new GameObject("MainThreadDispatcher");
DontDestroyOnLoad(go);
_instance = go.AddComponent<UnityMainThreadDispatcher>();
}
else
{
_instance = go.GetComponent<UnityMainThreadDispatcher>();
if (_instance == null)
_instance = go.AddComponent<UnityMainThreadDispatcher>();
}
}
return _instance;
}

public void Enqueue(Action action)
{
if (action == null) return;

lock (_executionQueue)
{
_executionQueue.Enqueue(action);
}
}

private void Update()
{
lock (_executionQueue)
{
while (_executionQueue.Count > 0)
{
_executionQueue.Dequeue()?.Invoke();
}
}
}
}

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

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

相关文章

2025年10月小红书代理商实力榜:五家对比评测与避坑指南

一、引言 小红书月活已突破三亿,日均搜索量同比提升百分之六十以上,对快消、美妆、餐饮、家装等赛道而言,它既是新品首发场,也是用户决策链的关键节点。品牌方、创业者、电商采购者在筛选代理商时,普遍面临三大痛…

设计模式(C++)详解——备忘录模式(1) - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

P1725 琪露诺 解题笔记

原题链接 我会暴力dp! 设 \(dp_i\) 为刚好到第 \(i\) 个格子的最大值。那么 \(dp_i\) 就可以从 \([i - RR, i - LL]\) 这段区间内转移。 则可以得出状态转移方程 \(dp_i = dp_{j} + a_i\) (\(j\) 在 \([i - RR, i - …

【电商行业案例】基于Vaadin全栈Java框架,打造百万级订单的B2B电商SaaS平台

在全球B2B电商领域,意大利SaaS平台 Rewix 正在用全新的方式重塑企业间的数字化交易体验。借助 Vaadin 全栈 Java 框架,Rewix 成功将传统的电商后台系统升级为现代化、可扩展的企业级 SaaS 平台——实现了每家客户百万…

【触想智能】什么是人脸识别一体机,人脸识别一体机主要应用于哪些领域?

人脸识别作为一项崭新的技术,正在迅速改变人们对于安全和便捷的认知。人脸识别技术的广泛应用,推动了人脸识别一体机的兴起。那么,什么是人脸识别一体机,以及这种设备主要应用于哪些领域呢?触想人脸识别一体机在智…

文档智能处理桌面软件开源

一.简介 本次针对「OCR识别」「文档比对」「文档图片处理」「视频转PPT/PDF」四款核心工具完成更新,从稳定性、轻量化、易用性三大维度优化体验,搭配全新名称与图标,让功能匹配更清晰,以下为详细内容。 二、体积压…

使用 LangChain 和 LangGraph 构建一个简单的多智能体系统

# 多智能体报告生成系统 本文介绍了一个简单的多智能体系统的实现,使用 LangChain 结合 LangGraph 来构建这样的系统,LangGraph 作为 LangChain 生态的重要组成部分,专为构建有状态、多智能体的工作流而设计,非常适…

【能源与流程工业案例】KBC借助TeeChart 打造工业级数据可视化平台

在能源与流程工业的数字化转型进程中,数据可视化扮演着至关重要的角色。今天,我们为大家分享KBC如何借助Steema旗下TeeChart的强大图表引擎,成功构建了面向工业级仿真场景的高性能数据可视化平台的案例。在能源与流…

2025年10月上海装修公司口碑榜:千州装饰领衔对比评测排行

一、引言 在上海这样的一线城市,装修支出往往占据家庭总资产的显著比例,创业者、新婚家庭、改善型购房者普遍面临“预算有限、品质难控、工期拖延”三大痛点。为了把试错成本降到最低,用户需要一份基于最新行业动态…

WPF使用MediaCapture开发相机应用(二、相机预览优化)

之前初步做好了相机预览的功能,但回头越想越不对劲,预览的延时感觉有点高了,于是切出系统的相机应用对比了一下:可以看到系统的相机都跑到26.55了,我开发的相机才跑到26.42,慢了一百多毫秒,感觉需要狠狠的优化一…

自己动手做一款ChatExcel数据分析系统,智能分析 Excel 数据

在日常办公、业务分析或是学生处理作业数据时,Excel 表格几乎是大家离不开的数据处理工具。但传统的 Excel 分析往往需要掌握复杂的函数和代码知识,这让不少人在面对大量数据时望而却步。而今天,我要给大家介绍的 C…

ROS-Navigation Move_base 源码阅读学习--恢复行为recovery_behavior(旋转恢复行为、代价地图清理恢复行为) - 教程

ROS-Navigation Move_base 源码阅读学习--恢复行为recovery_behavior(旋转恢复行为、代价地图清理恢复行为) - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; …

2025年10月无缝钢管推荐榜:五强对比评测与采购指南

无缝钢管是能源、化工、锅炉、船舶、机械五大行业的“血管”,项目一旦开工,管材的到货节奏、材质合规性、壁厚均匀度直接决定施工周期和后期安检。2025年国内在建火电、炼化一体化、氢能储运项目同步推进,带动无缝钢…

2025年10月股票开户券商推荐:五大主流平台对比评测榜

一、引言 对于计划进入A股、港股或基金市场的个人投资者而言,选择一家合规稳健、服务成熟、成本可控的券商是迈出投资第一步的关键。开户流程是否顺畅、交易通道是否稳定、后续投顾与产品资源是否丰富,直接影响后续资…

万象EXCEL开发(十)excel 高级混合查询 ——东方仙盟金丹期 - 教程

万象EXCEL开发(十)excel 高级混合查询 ——东方仙盟金丹期 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "…

实用指南:构建AI智能体:五十二、反应式智能体:AI世界的条件反射,真的可以又快又稳

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

redis-(伪)主从集群搭建

redis-(伪)主从集群搭建为了避免Redis的单点故障问题,可以搭建一个redis集群,将数据备份到集群中的其他节点上,如果其中一个 redis节点宕机,则由集群中的其他节点顶上。redis的主从集群是一个“一主多从”的读写…

za3J5cHRvc+WvhueggeWOn+aWhw

dEMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJYQTQUXQBQVYUVLLTREVJYQTMKYRDMFDVFPJUDEEHZWETZYVGWHKKQETGFQJNCEGGWHKK?DQMCPFQZDQMMIAGPFXHQRLGTIMVMZJANQLVKQEDAGDVFRPJUNGEUNAQZGZLECGYUXUEENJTBJLBQCRTBJDFHRRYIZETKZEMVDU…

结对项目:小学四则运算题目的命令行程序

小学四则运算题目生成器项目报告 一.项目信息项目 内容这个作业属于哪个课程 软件工程这个作业要求在哪里 结对项目这个作业的目标 设计实现小学四则运算题目生成器,支持题目生成、答案计算、重复性检测和自动批改,并…

微信小程序使用formdata采用multipart方式上传文件

微信小程序使用formdata采用multipart方式上传文件参考:https://juejin.cn/post/7220769136209051703 1 简介在微信原生小程序中,对于上传文件(图片,文件,语音,视频)都有自己的api最后使用wx.uploadFile上传到服…