diff --git a/CHANGELOG.md b/CHANGELOG.md index 29588113..2922f202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ ## master +* (2022.09.22) 增加`SaveAsImage()`接口保存图表到图片 * (2022.09.21) 修复`InsertSerie()`接口不刷新图表的问题 * (2022.09.21) 优化`PolarChart`对`Line`热力图的支持 * (2022.09.20) 增加`PolarChart`对`Heatmap`热力图的支持 diff --git a/Editor/Charts/BaseChartEditor.cs b/Editor/Charts/BaseChartEditor.cs index 617d12ef..fc9f39d7 100644 --- a/Editor/Charts/BaseChartEditor.cs +++ b/Editor/Charts/BaseChartEditor.cs @@ -16,6 +16,7 @@ namespace XCharts.Editor public static readonly GUIContent btnAddComponent = new GUIContent("Add Main Component", ""); public static readonly GUIContent btnCovertXYAxis = new GUIContent("Covert XY Axis", ""); public static readonly GUIContent btnRebuildChartObject = new GUIContent("Rebuild Chart Object", ""); + public static readonly GUIContent btnSaveAsImage = new GUIContent("Save As Image", ""); public static readonly GUIContent btnCheckWarning = new GUIContent("Check Warning", ""); public static readonly GUIContent btnHideWarning = new GUIContent("Hide Warning", ""); } @@ -279,6 +280,10 @@ namespace XCharts.Editor { m_Chart.RebuildChartObject(); } + if (GUILayout.Button(Styles.btnSaveAsImage)) + { + m_Chart.SaveAsImage(); + } if (m_CheckWarning) { EditorGUILayout.BeginHorizontal(); diff --git a/Plugins.meta b/Plugins.meta new file mode 100644 index 00000000..a60003bb --- /dev/null +++ b/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6558d1464a47441d18df18c4a403b2f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Plugins/Download.jslib b/Plugins/Download.jslib new file mode 100644 index 00000000..cc5b8886 --- /dev/null +++ b/Plugins/Download.jslib @@ -0,0 +1,24 @@ +mergeInto(LibraryManager.library, { + Download: function (str, fn) { + var msg = UTF8ToString(str); + var fname = UTF8ToString(fn); + function fixBinary(bin) { + var length = bin.length; + var buf = new ArrayBuffer(length); + var arr = new Uint8Array(buf); + for (var i = 0; i < length; i++) { + arr[i] = bin.charCodeAt(i); + } + return buf; + } + var binary = fixBinary(atob(msg)); + var data = new Blob([binary]); + var link = document.createElement('a'); + link.download = fname; + link.href = URL.createObjectURL(data); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +}); + diff --git a/Plugins/Download.jslib.meta b/Plugins/Download.jslib.meta new file mode 100644 index 00000000..c2c8647a --- /dev/null +++ b/Plugins/Download.jslib.meta @@ -0,0 +1,34 @@ +fileFormatVersion: 2 +guid: 821b9cd60f13648a396c76481da2191c +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + isOverridable: 0 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Facebook: WebGL + second: + enabled: 1 + settings: {} + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Internal/BaseChart.API.cs b/Runtime/Internal/BaseChart.API.cs index 765355c1..68c279cc 100644 --- a/Runtime/Internal/BaseChart.API.cs +++ b/Runtime/Internal/BaseChart.API.cs @@ -588,5 +588,15 @@ namespace XCharts.Runtime SerieHelper.GetItemColor(out color, out toColor, serie, null, m_Theme); return color; } + + /// + /// 保存图表为图片。 + /// + /// type of image: png, jpg, exr + /// save path + public void SaveAsImage(string imageType = "png", string savePath = "") + { + StartCoroutine(SaveAsImageSync(imageType, savePath)); + } } } \ No newline at end of file diff --git a/Runtime/Internal/BaseChart.cs b/Runtime/Internal/BaseChart.cs index 23cbca1e..f9ea93c1 100644 --- a/Runtime/Internal/BaseChart.cs +++ b/Runtime/Internal/BaseChart.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEngine; @@ -741,5 +742,11 @@ namespace XCharts.Runtime InitComponentHandlers(); InitSerieHandlers(); } + + private IEnumerator SaveAsImageSync(string imageType, string path) + { + yield return new WaitForEndOfFrame(); + ChartHelper.SaveAsImage(rectTransform, canvas, imageType, path); + } } } \ No newline at end of file diff --git a/Runtime/Internal/Utilities/ChartHelper.cs b/Runtime/Internal/Utilities/ChartHelper.cs index be19f64a..63025ade 100644 --- a/Runtime/Internal/Utilities/ChartHelper.cs +++ b/Runtime/Internal/Utilities/ChartHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using UnityEngine; @@ -896,5 +897,62 @@ namespace XCharts.Runtime if (valueOrRate >= -maxRate && valueOrRate <= maxRate) return valueOrRate * total; else return valueOrRate; } + + [DllImport("__Internal")] + private static extern void Download(string base64str, string fileName); + + public static Texture2D SaveAsImage(RectTransform rectTransform, Canvas canvas, string imageType = "png", string path = "") + { + var cam = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera; + var pos = RectTransformUtility.WorldToScreenPoint(cam, rectTransform.position); + var width = rectTransform.rect.width * canvas.scaleFactor; + var height = rectTransform.rect.height * canvas.scaleFactor; + var posX = pos.x + rectTransform.rect.xMin * canvas.scaleFactor; + var posY = pos.y + rectTransform.rect.yMin * canvas.scaleFactor; + var rect = new Rect(posX, posY, width, height); + var tex = new Texture2D((int) width, (int) height, TextureFormat.RGBA32, false); + tex.ReadPixels(rect, 0, 0); + tex.Apply(); + byte[] bytes; + switch (imageType) + { + case "png": + bytes = tex.EncodeToPNG(); + break; + case "jpg": + bytes = tex.EncodeToJPG(); + break; + case "exr": + bytes = tex.EncodeToEXR(); + break; + default: + Debug.LogError("SaveAsImage ERROR: not support image type:" + imageType); + return null; + } + var fileName = rectTransform.name + "." + imageType; +#if UNITY_WEBGL + string base64str = Convert.ToBase64String(bytes); + Download(base64str, fileName); + Debug.Log("SaveAsImage: download by brower:" + fileName); + return tex; +#endif + if (string.IsNullOrEmpty(path)) + { + var dir = Application.persistentDataPath + "/SavedImage"; +#if UNITY_EDITOR + dir = Application.dataPath + "/../SavedImage"; +#else + dir = Application.persistentDataPath + "/SavedImage"; +#endif + if (!System.IO.Directory.Exists(dir)) + { + System.IO.Directory.CreateDirectory(dir); + } + path = dir + "/" + fileName; + } + System.IO.File.WriteAllBytes(path, bytes); + Debug.Log("SaveAsImage:" + path); + return tex; + } } } \ No newline at end of file