improve:插入图片
This commit is contained in:
@@ -3,10 +3,11 @@ using System.Collections.Generic;
|
|||||||
using System.Windows.Ink;
|
using System.Windows.Ink;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using System.Windows; // Added for UIElement
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers
|
namespace Ink_Canvas.Helpers
|
||||||
{
|
{
|
||||||
public class TimeMachine
|
public partial class TimeMachine
|
||||||
{
|
{
|
||||||
private readonly List<TimeMachineHistory> _currentStrokeHistory = new List<TimeMachineHistory>();
|
private readonly List<TimeMachineHistory> _currentStrokeHistory = new List<TimeMachineHistory>();
|
||||||
|
|
||||||
@@ -139,6 +140,7 @@ namespace Ink_Canvas.Helpers
|
|||||||
//这里说一下 Tuple的 Value1 是初始值 ; Value 2 是改变值
|
//这里说一下 Tuple的 Value1 是初始值 ; Value 2 是改变值
|
||||||
public Dictionary<Stroke, Tuple<StylusPointCollection, StylusPointCollection>> StylusPointDictionary;
|
public Dictionary<Stroke, Tuple<StylusPointCollection, StylusPointCollection>> StylusPointDictionary;
|
||||||
public Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>> DrawingAttributes;
|
public Dictionary<Stroke, Tuple<DrawingAttributes, DrawingAttributes>> DrawingAttributes;
|
||||||
|
public UIElement InsertedElement; // 新增
|
||||||
public TimeMachineHistory(StrokeCollection currentStroke, TimeMachineHistoryType commitType, bool strokeHasBeenCleared)
|
public TimeMachineHistory(StrokeCollection currentStroke, TimeMachineHistoryType commitType, bool strokeHasBeenCleared)
|
||||||
{
|
{
|
||||||
CommitType = commitType;
|
CommitType = commitType;
|
||||||
@@ -163,6 +165,11 @@ namespace Ink_Canvas.Helpers
|
|||||||
StrokeHasBeenCleared = strokeHasBeenCleared;
|
StrokeHasBeenCleared = strokeHasBeenCleared;
|
||||||
ReplacedStroke = replacedStroke;
|
ReplacedStroke = replacedStroke;
|
||||||
}
|
}
|
||||||
|
public TimeMachineHistory(UIElement element, TimeMachineHistoryType commitType) // 新增
|
||||||
|
{
|
||||||
|
CommitType = commitType;
|
||||||
|
InsertedElement = element;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TimeMachineHistoryType
|
public enum TimeMachineHistoryType
|
||||||
@@ -171,6 +178,21 @@ namespace Ink_Canvas.Helpers
|
|||||||
ShapeRecognition,
|
ShapeRecognition,
|
||||||
Clear,
|
Clear,
|
||||||
Manipulation,
|
Manipulation,
|
||||||
DrawingAttributes
|
DrawingAttributes,
|
||||||
|
ElementInsert // 新增
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class TimeMachine // 新增partial,便于扩展
|
||||||
|
{
|
||||||
|
public void CommitElementInsertHistory(UIElement element)
|
||||||
|
{
|
||||||
|
if (_currentIndex + 1 < _currentStrokeHistory.Count)
|
||||||
|
{
|
||||||
|
_currentStrokeHistory.RemoveRange(_currentIndex + 1, (_currentStrokeHistory.Count - 1) - _currentIndex);
|
||||||
|
}
|
||||||
|
_currentStrokeHistory.Add(new TimeMachineHistory(element, TimeMachineHistoryType.ElementInsert));
|
||||||
|
_currentIndex = _currentStrokeHistory.Count - 1;
|
||||||
|
NotifyUndoRedoState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,9 @@ using System.Windows.Media;
|
|||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Ink_Canvas {
|
namespace Ink_Canvas {
|
||||||
public partial class MainWindow : Window {
|
public partial class MainWindow : Window {
|
||||||
@@ -23,6 +26,7 @@ namespace Ink_Canvas {
|
|||||||
private int WhiteboardTotalCount = 1;
|
private int WhiteboardTotalCount = 1;
|
||||||
private TimeMachineHistory[][] TimeMachineHistories = new TimeMachineHistory[101][]; //最多99页,0用来存储非白板时的墨迹以便还原
|
private TimeMachineHistory[][] TimeMachineHistories = new TimeMachineHistory[101][]; //最多99页,0用来存储非白板时的墨迹以便还原
|
||||||
|
|
||||||
|
// 保存每页白板图片信息
|
||||||
private void SaveStrokes(bool isBackupMain = false) {
|
private void SaveStrokes(bool isBackupMain = false) {
|
||||||
if (isBackupMain) {
|
if (isBackupMain) {
|
||||||
var timeMachineHistory = timeMachine.ExportTimeMachineHistory();
|
var timeMachineHistory = timeMachine.ExportTimeMachineHistory();
|
||||||
@@ -32,6 +36,26 @@ namespace Ink_Canvas {
|
|||||||
var timeMachineHistory = timeMachine.ExportTimeMachineHistory();
|
var timeMachineHistory = timeMachine.ExportTimeMachineHistory();
|
||||||
TimeMachineHistories[CurrentWhiteboardIndex] = timeMachineHistory;
|
TimeMachineHistories[CurrentWhiteboardIndex] = timeMachineHistory;
|
||||||
timeMachine.ClearStrokeHistory();
|
timeMachine.ClearStrokeHistory();
|
||||||
|
// 保存当前页图片信息
|
||||||
|
var elementInfos = new List<CanvasElementInfo>();
|
||||||
|
foreach (var child in inkCanvas.Children)
|
||||||
|
{
|
||||||
|
if (child is Image img && img.Source is BitmapImage bmp)
|
||||||
|
{
|
||||||
|
elementInfos.Add(new CanvasElementInfo
|
||||||
|
{
|
||||||
|
Type = "Image",
|
||||||
|
SourcePath = bmp.UriSource?.LocalPath ?? "",
|
||||||
|
Left = InkCanvas.GetLeft(img),
|
||||||
|
Top = InkCanvas.GetTop(img),
|
||||||
|
Width = img.Width,
|
||||||
|
Height = img.Height
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var savePath = Settings.Automation.AutoSavedStrokesLocation;
|
||||||
|
if (!Directory.Exists(savePath)) Directory.CreateDirectory(savePath);
|
||||||
|
File.WriteAllText(System.IO.Path.Combine(savePath, $"elements_page{CurrentWhiteboardIndex}.json"), JsonConvert.SerializeObject(elementInfos, Formatting.Indented));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +66,7 @@ namespace Ink_Canvas {
|
|||||||
_currentCommitType = CommitReason.UserInput;
|
_currentCommitType = CommitReason.UserInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 恢复每页白板图片信息
|
||||||
private void RestoreStrokes(bool isBackupMain = false) {
|
private void RestoreStrokes(bool isBackupMain = false) {
|
||||||
try {
|
try {
|
||||||
if (TimeMachineHistories[CurrentWhiteboardIndex] == null) return; //防止白板打开后不居中
|
if (TimeMachineHistories[CurrentWhiteboardIndex] == null) return; //防止白板打开后不居中
|
||||||
@@ -51,6 +76,29 @@ namespace Ink_Canvas {
|
|||||||
} else {
|
} else {
|
||||||
timeMachine.ImportTimeMachineHistory(TimeMachineHistories[CurrentWhiteboardIndex]);
|
timeMachine.ImportTimeMachineHistory(TimeMachineHistories[CurrentWhiteboardIndex]);
|
||||||
foreach (var item in TimeMachineHistories[CurrentWhiteboardIndex]) ApplyHistoryToCanvas(item);
|
foreach (var item in TimeMachineHistories[CurrentWhiteboardIndex]) ApplyHistoryToCanvas(item);
|
||||||
|
// 恢复当前页图片信息
|
||||||
|
inkCanvas.Children.Clear();
|
||||||
|
var savePath = Settings.Automation.AutoSavedStrokesLocation;
|
||||||
|
var elementsFile = System.IO.Path.Combine(savePath, $"elements_page{CurrentWhiteboardIndex}.json");
|
||||||
|
if (File.Exists(elementsFile))
|
||||||
|
{
|
||||||
|
var elementInfos = JsonConvert.DeserializeObject<List<CanvasElementInfo>>(File.ReadAllText(elementsFile));
|
||||||
|
foreach (var info in elementInfos)
|
||||||
|
{
|
||||||
|
if (info.Type == "Image" && File.Exists(info.SourcePath))
|
||||||
|
{
|
||||||
|
var img = new Image
|
||||||
|
{
|
||||||
|
Source = new BitmapImage(new Uri(info.SourcePath)),
|
||||||
|
Width = info.Width,
|
||||||
|
Height = info.Height
|
||||||
|
};
|
||||||
|
InkCanvas.SetLeft(img, info.Left);
|
||||||
|
InkCanvas.SetTop(img, info.Top);
|
||||||
|
inkCanvas.Children.Add(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
|
|||||||
@@ -0,0 +1,181 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
namespace Ink_Canvas
|
||||||
|
{
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
#region Image
|
||||||
|
private async void BtnImageInsert_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
||||||
|
openFileDialog.Filter = "Image files (*.jpg; *.jpeg; *.png; *.bmp)|*.jpg;*.jpeg;*.png;*.bmp";
|
||||||
|
|
||||||
|
if (openFileDialog.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
string filePath = openFileDialog.FileName;
|
||||||
|
|
||||||
|
Image image = await CreateAndCompressImageAsync(filePath);
|
||||||
|
|
||||||
|
if (image != null)
|
||||||
|
{
|
||||||
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
|
image.Name = timestamp;
|
||||||
|
|
||||||
|
CenterAndScaleElement(image);
|
||||||
|
|
||||||
|
InkCanvas.SetLeft(image, 0);
|
||||||
|
InkCanvas.SetTop(image, 0);
|
||||||
|
inkCanvas.Children.Add(image);
|
||||||
|
|
||||||
|
timeMachine.CommitElementInsertHistory(image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Image> CreateAndCompressImageAsync(string filePath)
|
||||||
|
{
|
||||||
|
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
||||||
|
if (!Directory.Exists(savePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(savePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string fileExtension = Path.GetExtension(filePath);
|
||||||
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
|
string newFilePath = Path.Combine(savePath, timestamp + fileExtension);
|
||||||
|
|
||||||
|
await Task.Run(() => File.Copy(filePath, newFilePath, true));
|
||||||
|
|
||||||
|
return await Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
BitmapImage bitmapImage = new BitmapImage();
|
||||||
|
bitmapImage.BeginInit();
|
||||||
|
bitmapImage.UriSource = new Uri(newFilePath);
|
||||||
|
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||||
|
bitmapImage.EndInit();
|
||||||
|
|
||||||
|
int width = bitmapImage.PixelWidth;
|
||||||
|
int height = bitmapImage.PixelHeight;
|
||||||
|
|
||||||
|
Image image = new Image();
|
||||||
|
if (isLoaded && Settings.Canvas.IsCompressPicturesUploaded && (width > 1920 || height > 1080))
|
||||||
|
{
|
||||||
|
double scaleX = 1920.0 / width;
|
||||||
|
double scaleY = 1080.0 / height;
|
||||||
|
double scale = Math.Min(scaleX, scaleY);
|
||||||
|
|
||||||
|
TransformedBitmap transformedBitmap = new TransformedBitmap(bitmapImage, new ScaleTransform(scale, scale));
|
||||||
|
|
||||||
|
image.Source = transformedBitmap;
|
||||||
|
image.Width = transformedBitmap.PixelWidth;
|
||||||
|
image.Height = transformedBitmap.PixelHeight;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
image.Source = bitmapImage;
|
||||||
|
image.Width = width;
|
||||||
|
image.Height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Media
|
||||||
|
private async void BtnMediaInsert_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
OpenFileDialog openFileDialog = new OpenFileDialog();
|
||||||
|
openFileDialog.Filter = "Media files (*.mp4; *.avi; *.wmv)|*.mp4;*.avi;*.wmv";
|
||||||
|
|
||||||
|
if (openFileDialog.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
string filePath = openFileDialog.FileName;
|
||||||
|
|
||||||
|
byte[] mediaBytes = await Task.Run(() => File.ReadAllBytes(filePath));
|
||||||
|
|
||||||
|
MediaElement mediaElement = await CreateMediaElementAsync(filePath);
|
||||||
|
|
||||||
|
if (mediaElement != null)
|
||||||
|
{
|
||||||
|
CenterAndScaleElement(mediaElement);
|
||||||
|
|
||||||
|
InkCanvas.SetLeft(mediaElement, 0);
|
||||||
|
InkCanvas.SetTop(mediaElement, 0);
|
||||||
|
inkCanvas.Children.Add(mediaElement);
|
||||||
|
|
||||||
|
mediaElement.LoadedBehavior = MediaState.Manual;
|
||||||
|
mediaElement.UnloadedBehavior = MediaState.Manual;
|
||||||
|
mediaElement.Loaded += async (_, args) =>
|
||||||
|
{
|
||||||
|
mediaElement.Play();
|
||||||
|
await Task.Delay(100);
|
||||||
|
mediaElement.Pause();
|
||||||
|
};
|
||||||
|
|
||||||
|
timeMachine.CommitElementInsertHistory(mediaElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<MediaElement> CreateMediaElementAsync(string filePath)
|
||||||
|
{
|
||||||
|
string savePath = Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
||||||
|
if (!Directory.Exists(savePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(savePath);
|
||||||
|
}
|
||||||
|
return await Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
MediaElement mediaElement = new MediaElement();
|
||||||
|
mediaElement.Source = new Uri(filePath);
|
||||||
|
string timestamp = "media_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
|
mediaElement.Name = timestamp;
|
||||||
|
mediaElement.LoadedBehavior = MediaState.Manual;
|
||||||
|
mediaElement.UnloadedBehavior = MediaState.Manual;
|
||||||
|
|
||||||
|
mediaElement.Width = 256;
|
||||||
|
mediaElement.Height = 256;
|
||||||
|
|
||||||
|
string fileExtension = Path.GetExtension(filePath);
|
||||||
|
string newFilePath = Path.Combine(savePath, mediaElement.Name + fileExtension);
|
||||||
|
|
||||||
|
File.Copy(filePath, newFilePath, true);
|
||||||
|
|
||||||
|
mediaElement.Source = new Uri(newFilePath);
|
||||||
|
|
||||||
|
return mediaElement;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void CenterAndScaleElement(FrameworkElement element)
|
||||||
|
{
|
||||||
|
double maxWidth = SystemParameters.PrimaryScreenWidth / 2;
|
||||||
|
double maxHeight = SystemParameters.PrimaryScreenHeight / 2;
|
||||||
|
|
||||||
|
double scaleX = maxWidth / element.Width;
|
||||||
|
double scaleY = maxHeight / element.Height;
|
||||||
|
double scale = Math.Min(scaleX, scaleY);
|
||||||
|
|
||||||
|
TransformGroup transformGroup = new TransformGroup();
|
||||||
|
transformGroup.Children.Add(new ScaleTransform(scale, scale));
|
||||||
|
|
||||||
|
double canvasWidth = inkCanvas.ActualWidth;
|
||||||
|
double canvasHeight = inkCanvas.ActualHeight;
|
||||||
|
double centerX = (canvasWidth - element.Width * scale) / 2;
|
||||||
|
double centerY = (canvasHeight - element.Height * scale) / 2;
|
||||||
|
|
||||||
|
transformGroup.Children.Add(new TranslateTransform(centerX, centerY));
|
||||||
|
|
||||||
|
element.RenderTransform = transformGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1766,6 +1766,9 @@ namespace Ink_Canvas {
|
|||||||
ClearStrokes(true);
|
ClearStrokes(true);
|
||||||
RestoreStrokes();
|
RestoreStrokes();
|
||||||
|
|
||||||
|
// 退出白板时清空图片
|
||||||
|
inkCanvas.Children.Clear();
|
||||||
|
|
||||||
if (BtnSwitchTheme.Content.ToString() == "浅色") {
|
if (BtnSwitchTheme.Content.ToString() == "浅色") {
|
||||||
BtnSwitch.Content = "黑板";
|
BtnSwitch.Content = "黑板";
|
||||||
BtnExit.Foreground = Brushes.White;
|
BtnExit.Foreground = Brushes.White;
|
||||||
@@ -1774,12 +1777,10 @@ namespace Ink_Canvas {
|
|||||||
BtnSwitch.Content = "白板";
|
BtnSwitch.Content = "白板";
|
||||||
if (isPresentationHaveBlackSpace) {
|
if (isPresentationHaveBlackSpace) {
|
||||||
BtnExit.Foreground = Brushes.White;
|
BtnExit.Foreground = Brushes.White;
|
||||||
//SymbolIconBtnColorBlackContent.Foreground = Brushes.White;
|
|
||||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BtnExit.Foreground = Brushes.Black;
|
BtnExit.Foreground = Brushes.Black;
|
||||||
//SymbolIconBtnColorBlackContent.Foreground = Brushes.White;
|
|
||||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1803,22 +1804,22 @@ namespace Ink_Canvas {
|
|||||||
ClearStrokes(true);
|
ClearStrokes(true);
|
||||||
RestoreStrokes(true);
|
RestoreStrokes(true);
|
||||||
|
|
||||||
|
// 退出白板时清空图片
|
||||||
|
inkCanvas.Children.Clear();
|
||||||
|
|
||||||
if (BtnSwitchTheme.Content.ToString() == "浅色") {
|
if (BtnSwitchTheme.Content.ToString() == "浅色") {
|
||||||
BtnSwitch.Content = "黑板";
|
BtnSwitch.Content = "黑板";
|
||||||
BtnExit.Foreground = Brushes.White;
|
BtnExit.Foreground = Brushes.White;
|
||||||
//SymbolIconBtnColorBlackContent.Foreground = Brushes.Black;
|
|
||||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BtnSwitch.Content = "白板";
|
BtnSwitch.Content = "白板";
|
||||||
if (isPresentationHaveBlackSpace) {
|
if (isPresentationHaveBlackSpace) {
|
||||||
BtnExit.Foreground = Brushes.White;
|
BtnExit.Foreground = Brushes.White;
|
||||||
//SymbolIconBtnColorBlackContent.Foreground = Brushes.White;
|
|
||||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BtnExit.Foreground = Brushes.Black;
|
BtnExit.Foreground = Brushes.Black;
|
||||||
//SymbolIconBtnColorBlackContent.Foreground = Brushes.White;
|
|
||||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1840,12 +1841,10 @@ namespace Ink_Canvas {
|
|||||||
BtnSwitch.Content = "屏幕";
|
BtnSwitch.Content = "屏幕";
|
||||||
if (BtnSwitchTheme.Content.ToString() == "浅色") {
|
if (BtnSwitchTheme.Content.ToString() == "浅色") {
|
||||||
BtnExit.Foreground = Brushes.White;
|
BtnExit.Foreground = Brushes.White;
|
||||||
//SymbolIconBtnColorBlackContent.Foreground = Brushes.Black;
|
|
||||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BtnExit.Foreground = Brushes.Black;
|
BtnExit.Foreground = Brushes.Black;
|
||||||
//SymbolIconBtnColorBlackContent.Foreground = Brushes.White;
|
|
||||||
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1990,53 +1989,6 @@ namespace Ink_Canvas {
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建并压缩图片的异步方法
|
|
||||||
/// </summary>
|
|
||||||
private async Task<Image> CreateAndCompressImageAsync(string filePath)
|
|
||||||
{
|
|
||||||
string savePath = System.IO.Path.Combine(Settings.Automation.AutoSavedStrokesLocation, "File Dependency");
|
|
||||||
if (!System.IO.Directory.Exists(savePath))
|
|
||||||
System.IO.Directory.CreateDirectory(savePath);
|
|
||||||
|
|
||||||
string fileExtension = System.IO.Path.GetExtension(filePath);
|
|
||||||
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
|
||||||
string newFilePath = System.IO.Path.Combine(savePath, timestamp + fileExtension);
|
|
||||||
|
|
||||||
await Task.Run(() => System.IO.File.Copy(filePath, newFilePath, true));
|
|
||||||
|
|
||||||
return await Dispatcher.InvokeAsync(() =>
|
|
||||||
{
|
|
||||||
var bitmapImage = new BitmapImage();
|
|
||||||
bitmapImage.BeginInit();
|
|
||||||
bitmapImage.UriSource = new Uri(newFilePath);
|
|
||||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
|
||||||
bitmapImage.EndInit();
|
|
||||||
|
|
||||||
int width = bitmapImage.PixelWidth;
|
|
||||||
int height = bitmapImage.PixelHeight;
|
|
||||||
|
|
||||||
Image image = new Image();
|
|
||||||
if (Settings.Canvas.IsCompressPicturesUploaded && (width > 1920 || height > 1080))
|
|
||||||
{
|
|
||||||
double scaleX = 1920.0 / width;
|
|
||||||
double scaleY = 1080.0 / height;
|
|
||||||
double scale = Math.Min(scaleX, scaleY);
|
|
||||||
var transformedBitmap = new TransformedBitmap(bitmapImage, new ScaleTransform(scale, scale));
|
|
||||||
image.Source = transformedBitmap;
|
|
||||||
image.Width = transformedBitmap.PixelWidth;
|
|
||||||
image.Height = transformedBitmap.PixelHeight;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
image.Source = bitmapImage;
|
|
||||||
image.Width = width;
|
|
||||||
image.Height = height;
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void InsertImage_MouseUp(object sender, MouseButtonEventArgs e)
|
private async void InsertImage_MouseUp(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
var dialog = new Microsoft.Win32.OpenFileDialog
|
var dialog = new Microsoft.Win32.OpenFileDialog
|
||||||
@@ -2045,9 +1997,21 @@ namespace Ink_Canvas {
|
|||||||
};
|
};
|
||||||
if (dialog.ShowDialog() == true)
|
if (dialog.ShowDialog() == true)
|
||||||
{
|
{
|
||||||
var image = await CreateAndCompressImageAsync(dialog.FileName);
|
string filePath = dialog.FileName;
|
||||||
// TODO: 这里可以将image添加到画布或其他控件
|
Image image = await CreateAndCompressImageAsync(filePath); // 补充image定义
|
||||||
MessageBox.Show("图片已处理完成,可在此处插入到画布。");
|
if (image != null)
|
||||||
|
{
|
||||||
|
string timestamp = "img_" + DateTime.Now.ToString("yyyyMMdd_HH_mm_ss_fff");
|
||||||
|
image.Name = timestamp;
|
||||||
|
|
||||||
|
CenterAndScaleElement(image);
|
||||||
|
|
||||||
|
InkCanvas.SetLeft(image, 0);
|
||||||
|
InkCanvas.SetTop(image, 0);
|
||||||
|
inkCanvas.Children.Add(image);
|
||||||
|
|
||||||
|
timeMachine.CommitElementInsertHistory(image);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,19 @@ using System.Windows.Forms;
|
|||||||
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
|
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace Ink_Canvas {
|
namespace Ink_Canvas {
|
||||||
|
// 1. 定义元素信息结构
|
||||||
|
public class CanvasElementInfo
|
||||||
|
{
|
||||||
|
public string Type { get; set; } // "Image"
|
||||||
|
public string SourcePath { get; set; }
|
||||||
|
public double Left { get; set; }
|
||||||
|
public double Top { get; set; }
|
||||||
|
public double Width { get; set; }
|
||||||
|
public double Height { get; set; }
|
||||||
|
}
|
||||||
public partial class MainWindow : Window {
|
public partial class MainWindow : Window {
|
||||||
private void SymbolIconSaveStrokes_MouseUp(object sender, MouseButtonEventArgs e) {
|
private void SymbolIconSaveStrokes_MouseUp(object sender, MouseButtonEventArgs e) {
|
||||||
if (lastBorderMouseDownObject != sender || inkCanvas.Visibility != Visibility.Visible) return;
|
if (lastBorderMouseDownObject != sender || inkCanvas.Visibility != Visibility.Visible) return;
|
||||||
@@ -108,6 +119,24 @@ namespace Ink_Canvas {
|
|||||||
var fs = new FileStream(savePathWithName, FileMode.Create);
|
var fs = new FileStream(savePathWithName, FileMode.Create);
|
||||||
inkCanvas.Strokes.Save(fs);
|
inkCanvas.Strokes.Save(fs);
|
||||||
fs.Close();
|
fs.Close();
|
||||||
|
// 保存元素信息
|
||||||
|
var elementInfos = new List<CanvasElementInfo>();
|
||||||
|
foreach (var child in inkCanvas.Children)
|
||||||
|
{
|
||||||
|
if (child is Image img && img.Source is BitmapImage bmp)
|
||||||
|
{
|
||||||
|
elementInfos.Add(new CanvasElementInfo
|
||||||
|
{
|
||||||
|
Type = "Image",
|
||||||
|
SourcePath = bmp.UriSource?.LocalPath ?? "",
|
||||||
|
Left = InkCanvas.GetLeft(img),
|
||||||
|
Top = InkCanvas.GetTop(img),
|
||||||
|
Width = img.Width,
|
||||||
|
Height = img.Height
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File.WriteAllText(Path.ChangeExtension(savePathWithName, ".elements.json"), JsonConvert.SerializeObject(elementInfos, Formatting.Indented));
|
||||||
if (newNotice) ShowNotification("墨迹成功保存至 " + savePathWithName);
|
if (newNotice) ShowNotification("墨迹成功保存至 " + savePathWithName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -573,6 +602,28 @@ namespace Ink_Canvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 恢复元素信息
|
||||||
|
var elementsFile = Path.ChangeExtension(filePath, ".elements.json");
|
||||||
|
if (File.Exists(elementsFile))
|
||||||
|
{
|
||||||
|
var elementInfos = JsonConvert.DeserializeObject<List<CanvasElementInfo>>(File.ReadAllText(elementsFile));
|
||||||
|
foreach (var info in elementInfos)
|
||||||
|
{
|
||||||
|
if (info.Type == "Image" && File.Exists(info.SourcePath))
|
||||||
|
{
|
||||||
|
var img = new Image
|
||||||
|
{
|
||||||
|
Source = new BitmapImage(new Uri(info.SourcePath)),
|
||||||
|
Width = info.Width,
|
||||||
|
Height = info.Height
|
||||||
|
};
|
||||||
|
InkCanvas.SetLeft(img, info.Left);
|
||||||
|
InkCanvas.SetTop(img, info.Top);
|
||||||
|
inkCanvas.Children.Add(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (fileStreamHasNoStroke)
|
if (fileStreamHasNoStroke)
|
||||||
using (var ms = new MemoryStream(File.ReadAllBytes(filePath))) {
|
using (var ms = new MemoryStream(File.ReadAllBytes(filePath))) {
|
||||||
ms.Seek(0, SeekOrigin.Begin);
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
|||||||
@@ -130,6 +130,16 @@ namespace Ink_Canvas {
|
|||||||
if (canvas.Strokes.Contains(currentStroke))
|
if (canvas.Strokes.Contains(currentStroke))
|
||||||
canvas.Strokes.Remove(currentStroke);
|
canvas.Strokes.Remove(currentStroke);
|
||||||
}
|
}
|
||||||
|
} else if (item.CommitType == TimeMachineHistoryType.ElementInsert) {
|
||||||
|
if (!item.StrokeHasBeenCleared) {
|
||||||
|
// Undo: 移除元素
|
||||||
|
if (item.InsertedElement != null && inkCanvas.Children.Contains(item.InsertedElement))
|
||||||
|
inkCanvas.Children.Remove(item.InsertedElement);
|
||||||
|
} else {
|
||||||
|
// Redo: 添加元素
|
||||||
|
if (item.InsertedElement != null && !inkCanvas.Children.Contains(item.InsertedElement))
|
||||||
|
inkCanvas.Children.Add(item.InsertedElement);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentCommitType = CommitReason.UserInput;
|
_currentCommitType = CommitReason.UserInput;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace Ink_Canvas
|
|||||||
[JsonProperty("hyperbolaAsymptoteOption")]
|
[JsonProperty("hyperbolaAsymptoteOption")]
|
||||||
public OptionalOperation HyperbolaAsymptoteOption { get; set; } = OptionalOperation.Ask;
|
public OptionalOperation HyperbolaAsymptoteOption { get; set; } = OptionalOperation.Ask;
|
||||||
[JsonProperty("isCompressPicturesUploaded")]
|
[JsonProperty("isCompressPicturesUploaded")]
|
||||||
public bool IsCompressPicturesUploaded { get; set; } = true;
|
public bool IsCompressPicturesUploaded { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OptionalOperation
|
public enum OptionalOperation
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ TRACE;DEBUG;NETFRAMEWORK;NET472;;NET30_OR_GREATER;NET35_OR_GREATER;NET40_OR_GREA
|
|||||||
E:\ICC CE\ICC CE main\community\Ink Canvas\App.xaml
|
E:\ICC CE\ICC CE main\community\Ink Canvas\App.xaml
|
||||||
21348134359
|
21348134359
|
||||||
|
|
||||||
74373288771
|
752071346691
|
||||||
471037513499
|
471037513499
|
||||||
Helpers\Plugins\BuiltIn\SuperLauncher\LauncherSettingsControl.xaml;Helpers\Plugins\BuiltIn\SuperLauncher\LauncherWindow.xaml;MainWindow.xaml;MainWindow_cs\MW_Eraser.xaml;Resources\DrawShapeImageDictionary.xaml;Resources\IconImageDictionary.xaml;Resources\SeewoImageDictionary.xaml;Resources\Styles\Dark.xaml;Resources\Styles\Light.xaml;Windows\AddCustomIconWindow.xaml;Windows\AddPickNameBackgroundWindow.xaml;Windows\CountdownTimerWindow.xaml;Windows\CustomIconWindow.xaml;Windows\CycleProcessBar.xaml;Windows\HasNewUpdateWindow.xaml;Windows\ManagePickNameBackgroundsWindow.xaml;Windows\NamesInputWindow.xaml;Windows\OperatingGuideWindow.xaml;Windows\PluginSettingsWindow.xaml;Windows\RandWindow.xaml;Windows\YesOrNoNotificationWindow.xaml;
|
Helpers\Plugins\BuiltIn\SuperLauncher\LauncherSettingsControl.xaml;Helpers\Plugins\BuiltIn\SuperLauncher\LauncherWindow.xaml;MainWindow.xaml;MainWindow_cs\MW_Eraser.xaml;Resources\DrawShapeImageDictionary.xaml;Resources\IconImageDictionary.xaml;Resources\SeewoImageDictionary.xaml;Resources\Styles\Dark.xaml;Resources\Styles\Light.xaml;Windows\AddCustomIconWindow.xaml;Windows\AddPickNameBackgroundWindow.xaml;Windows\CountdownTimerWindow.xaml;Windows\CustomIconWindow.xaml;Windows\CycleProcessBar.xaml;Windows\HasNewUpdateWindow.xaml;Windows\ManagePickNameBackgroundsWindow.xaml;Windows\NamesInputWindow.xaml;Windows\OperatingGuideWindow.xaml;Windows\PluginSettingsWindow.xaml;Windows\RandWindow.xaml;Windows\YesOrNoNotificationWindow.xaml;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user