PictureDataManager.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using ET;
  6. using UnityEngine;
  7. using UnityEngine.Networking;
  8. namespace GFGGame
  9. {
  10. public class PictureDataManager : SingletonBase<PictureDataManager>
  11. {
  12. //本地地址
  13. private const string _loadUrl = "gfgpicture";
  14. //正在操作的文件队列
  15. private Queue<string> _queueOperateFileList = new Queue<string>();
  16. /// <summary>
  17. /// 所有照片的二进制
  18. /// </summary>
  19. private Dictionary<string, Texture2D> _allPicByteDic = new Dictionary<string, Texture2D>();
  20. public async ETTask<Texture2D> GetPicNTexture(string tempUrl)
  21. {
  22. string fileNameKey = GetUrlFileName(tempUrl);
  23. if (_allPicByteDic.TryGetValue(fileNameKey, out Texture2D texture2D))
  24. {
  25. // 可能存在
  26. if (texture2D != null &&
  27. texture2D.width > 0 &&
  28. texture2D.height > 0 &&
  29. texture2D.GetPixels().Length > 0)
  30. {
  31. // 检查纹理的格式是否支持
  32. if (texture2D.format == TextureFormat.RGBA32 ||
  33. texture2D.format == TextureFormat.RGB24)
  34. {
  35. // 纹理有效,可以正常显示
  36. return texture2D; // 或者转换为 NTexture 对象
  37. }
  38. else
  39. {
  40. Debug.LogError("Texture format is not supported.");
  41. // 处理不支持的纹理格式
  42. return await DownloadOrLoadPic(tempUrl);
  43. }
  44. }
  45. else
  46. {
  47. Debug.LogWarning("Texture is invalid or has no pixels.");
  48. // 处理无效的纹理
  49. return await DownloadOrLoadPic(tempUrl);
  50. }
  51. }
  52. //TODO 一定不存在, 需要去进行下载
  53. return await DownloadOrLoadPic(tempUrl);
  54. }
  55. //从远端进行下载
  56. public async ETTask<Texture2D> DownloadOrLoadPic(string tempUrl)
  57. {
  58. string fileName = GetUrlFileName(tempUrl);
  59. Texture2D texture2D = await DownloadPictureAsync(tempUrl);
  60. if (texture2D == null)
  61. {
  62. return GetDefaultTexture();
  63. }
  64. //不为null, 以协程的方式存储到内存以及, 本地
  65. _allPicByteDic[fileName] = texture2D;
  66. //加入队列
  67. _queueOperateFileList.Enqueue(fileName);
  68. SavaPicToLoad().Coroutine();
  69. return texture2D;
  70. }
  71. //存储图片文件到本地,如果存在就进行删除本地或者覆盖,以当前的为最新的进行记录
  72. public async ETTask SavaPicToLoad()
  73. {
  74. var tempList = _queueOperateFileList.ToList();
  75. for (int i = 0; i < tempList.Count; i++)
  76. {
  77. if (_queueOperateFileList.Count == 0)
  78. {
  79. break;
  80. }
  81. string fileName = _queueOperateFileList.Dequeue();
  82. if (string.IsNullOrEmpty(fileName))
  83. {
  84. continue;
  85. }
  86. if (!_allPicByteDic.TryGetValue(fileName, out Texture2D texture2D))
  87. {
  88. continue;
  89. }
  90. if (texture2D == null)
  91. {
  92. continue;
  93. }
  94. // 获取本地存储路径
  95. string localPath = Path.Combine(Application.persistentDataPath, fileName);
  96. // 存储图片文件到本地
  97. try
  98. {
  99. // 将 Texture2D 转换为字节数组
  100. byte[] imageData = texture2D.EncodeToPNG();
  101. // 如果文件已经存在,则覆盖
  102. if (File.Exists(localPath))
  103. {
  104. File.Delete(localPath);
  105. }
  106. // 将字节数组写入文件
  107. File.WriteAllBytes(localPath, imageData);
  108. }
  109. catch (Exception ex)
  110. {
  111. Debug.LogError($"Failed to save image to local path: {ex.Message}");
  112. }
  113. }
  114. await ETTask.CompletedTask;
  115. }
  116. private async ETTask<Texture2D> DownloadPictureAsync(string tempUrl, int count = 0)
  117. {
  118. string fileName = GetUrlFileName(tempUrl);
  119. if (count >= 3)
  120. {
  121. PromptController.Instance.ShowFloatTextPrompt("下载失败");
  122. ViewManager.Hide<ModalStatusView>();
  123. return null;
  124. }
  125. using (UnityWebRequest request = UnityWebRequestTexture.GetTexture(tempUrl))
  126. {
  127. var asyncOperation = request.SendWebRequest();
  128. while (!asyncOperation.isDone)
  129. {
  130. await TimerComponent.Instance.WaitTillAsync(100); // 等待一段时间后继续检查
  131. }
  132. if (request.result == UnityWebRequest.Result.ProtocolError ||
  133. request.result == UnityWebRequest.Result.ConnectionError)
  134. {
  135. count += 1;
  136. return await DownloadPictureAsync(tempUrl, count); // 递归重试
  137. }
  138. else
  139. {
  140. Texture2D texture = (request.downloadHandler as DownloadHandlerTexture).texture;
  141. return texture;
  142. }
  143. }
  144. }
  145. // 获取存储文件的完整路径
  146. public static string GetFilePath(string fileName)
  147. {
  148. // 获取持久化数据路径
  149. string persistentDataPath = Application.persistentDataPath;
  150. // 创建“zhaoPian”文件夹路径
  151. string folderPath = Path.Combine(persistentDataPath, _loadUrl);
  152. // 确保文件夹存在
  153. if (!Directory.Exists(folderPath))
  154. {
  155. Directory.CreateDirectory(folderPath);
  156. }
  157. // 返回文件的完整路径
  158. return Path.Combine(folderPath, fileName);
  159. }
  160. /// <summary>
  161. /// 获取下载地址的文件名, 包含后缀 TODO 需要增加容错
  162. /// </summary>
  163. /// <param name="url"></param>
  164. /// <returns></returns>
  165. public static string GetUrlFileName(string url)
  166. {
  167. // 创建一个 Uri 对象
  168. Uri uri = new Uri(url);
  169. // 获取 URL 的路径部分
  170. string path = uri.AbsolutePath;
  171. // 从路径中提取文件名
  172. string fileName = System.IO.Path.GetFileName(path);
  173. // // 获取不包含扩展名的文件名
  174. // string fileNameWithoutExtension = System.IO.Path.GetFileNameWithoutExtension(fileName);
  175. return fileName;
  176. }
  177. //TODO 默认纹理, 让客户端来修改这个代码, 定义一个默认的 Texture2D
  178. private Texture2D GetDefaultTexture()
  179. {
  180. // 创建一个简单的默认图片,比如纯色或空白图片
  181. Texture2D defaultTexture = new Texture2D(2, 2);
  182. Color[] pixels = defaultTexture.GetPixels();
  183. for (int i = 0; i < pixels.Length; i++)
  184. {
  185. pixels[i] = Color.gray; // 设置为灰色的默认图片
  186. }
  187. defaultTexture.SetPixels(pixels);
  188. defaultTexture.Apply();
  189. return defaultTexture;
  190. }
  191. //初始化的时候根据图片保存时间, 加载最多50条到内存中
  192. public void LoadAllImages()
  193. {
  194. // 获取文件夹路径
  195. string folderPath = Path.Combine(Application.persistentDataPath, _loadUrl);
  196. // 检查文件夹是否存在
  197. if (Directory.Exists(folderPath))
  198. {
  199. // 获取所有图片文件路径(假设图片格式为.jpg和.png)
  200. string[] imageFiles = Directory.GetFiles(folderPath, "*.*", SearchOption.TopDirectoryOnly);
  201. // 过滤出图片文件,并按修改时间排序
  202. var imageFileInfos = imageFiles
  203. .Where(filePath => filePath.EndsWith(".jpg") || filePath.EndsWith(".png"))
  204. .Select(filePath => new FileInfo(filePath))
  205. .OrderByDescending(fileInfo => fileInfo.LastWriteTime)
  206. .ToList();
  207. int loadedCount = 0;
  208. const int maxImagesToLoad = 50;
  209. foreach (var fileInfo in imageFileInfos)
  210. {
  211. string filePath = fileInfo.FullName;
  212. try
  213. {
  214. // 读取图片数据
  215. byte[] imageData = File.ReadAllBytes(filePath);
  216. // 创建纹理并加载数据
  217. Texture2D texture = new Texture2D(2, 2); // 创建一个2x2的空纹理
  218. if (texture.LoadImage(imageData))
  219. {
  220. // 提取文件名作为字典的键
  221. string fileName = Path.GetFileName(filePath);
  222. // 将纹理添加到字典
  223. _allPicByteDic[fileName] = texture;
  224. Debug.Log($"Loaded {fileName}");
  225. loadedCount++;
  226. // 如果已经加载了最大数量的图片,停止加载并删除剩余较旧的图片
  227. if (loadedCount >= maxImagesToLoad)
  228. {
  229. DeleteOldImages(imageFileInfos, loadedCount);
  230. return;
  231. }
  232. }
  233. else
  234. {
  235. Debug.LogWarning($"Failed to load image from {filePath}");
  236. }
  237. }
  238. catch
  239. {
  240. Debug.LogWarning($"Error processing file: {filePath}");
  241. }
  242. }
  243. }
  244. else
  245. {
  246. Debug.LogWarning($"Folder not found: {folderPath}");
  247. }
  248. }
  249. // 删除较旧的图片
  250. private void DeleteOldImages(List<FileInfo> imageFileInfos, int loadedCount)
  251. {
  252. // 从已经加载的图片后面开始删除
  253. for (int i = loadedCount; i < imageFileInfos.Count; i++)
  254. {
  255. string filePath = imageFileInfos[i].FullName;
  256. try
  257. {
  258. File.Delete(filePath);
  259. Debug.Log($"Deleted {filePath}");
  260. }
  261. catch (Exception ex)
  262. {
  263. Debug.LogWarning($"Failed to delete {filePath}: {ex.Message}");
  264. }
  265. }
  266. }
  267. }
  268. }