using AbleClassRoom.Mvvm;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
namespace AbleClassRoom.AbleControl
{
enum EventFlag
{
Zoom,
Crop,
Pan,
None
}
///
/// TextBookViewer.xaml에 대한 상호 작용 논리
///
///
public partial class TextBookViewer : BindableBaseControl
{
///
/// 교재 확대 완료 처리 이벤트 대리연산자
///
///
///
public delegate void ZoomedCompleted(object sender, ZoomedCompleteEventArgs args);
public event ZoomedCompleted OnZoomedCompleted;
///
/// 교재 잘라내기 (이미지 부분 캡쳐) 완료 처리 이벤트 대리연산자
///
///
///
public delegate void CroppedBitmapCompleted(object sender, CroppedBitmapCompleteEventArgs args);
public event CroppedBitmapCompleted OnCroppedBitmapCompleted;
///
/// 교재의 Nagative 처리여부
///
private bool _isNagative;
public bool IsNagative
{
get => _isNagative;
set
{
SetProperty(ref _isNagative, value);
}
}
System.Drawing.Bitmap CurrentTextBook;
///
/// 활성 교재 페이지 설정
///
///
///
private Uri _textBookUri; // = null; // { get; set; }
public Uri TextBookUri
{
get => _textBookUri;
set
{
//_textBookUri = value;
Dispatcher.Invoke(new Action(() =>
{
if (SetProperty(ref _textBookUri, value))
{
CurrentTextBook = new System.Drawing.Bitmap(_textBookUri.AbsolutePath);
inkCanvasImage.ImageSource = _isNagative ? ConvertBitmapToImageSource(Transform(CurrentTextBook)) : ConvertBitmapToImageSource(CurrentTextBook);
}
}));
}
}
private List _editControlCollection;
public List EditControlCollection
{
get => _editControlCollection;
set
{
SetProperty(ref _editControlCollection, value);
}
}
///
/// 현재 교재의 뷰어(InkCanvas) 객체
/// 강의실에서 제어를 위하여 접근하여 가져 갈 수 있게 처리
///
public InkCanvas RenderingInkCanvas
{
get => inkCanvas;
}
Point mouseDownPos; // 교재확대 및 캡쳐 등을 위한 마우스 최초 선택 영역
Point originTransformPos; // 교재확대 후 이동 처리에서 교재의 Transform에 대한 최초 위치값
bool isMouseDown = false; // 교재확대 및 캡쳐 등을 위한 마우스 제어 여부 (클릭 여부)
Point TextBookDownPoint = new Point();
Point ScrollViewerDownPoint = new Point();
Point EditControlLocationPos = new Point();
Point EditControlMouseDownPos = new Point();
ImageAttributes imageAttributes = new ImageAttributes(); // 교재의 Nagative 처리를 위한 이미지 속성
ColorMatrix colorMatrix; // 교재의 Nagative 처리를 위한 ColorMatrix 정의
EventFlag eventFlag;
public TextBookViewer()
{
InitializeComponent();
// create the negative color matrix
colorMatrix = new ColorMatrix(new float[][]
{
new float[] {-1, 0, 0, 0, 0},
new float[] {0, -1, 0, 0, 0},
new float[] {0, 0, -1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {1, 1, 1, 0, 1}
});
imageAttributes.SetColorMatrix(colorMatrix);
inkCanvas.DefaultDrawingAttributes.FitToCurve = false;
eventFlag = EventFlag.None;
inkCanvas.MouseLeftButtonDown += TextBookViewer_MarqueeZoomMouseLeftButtonDown;
inkCanvas.MouseMove += TextBookViewer_MarqueeZoomMouseMove;
inkCanvas.MouseLeftButtonUp += TextBookViewer_MarqueeZoomMouseLeftButtonUp;
this.Loaded += TextBookViewer_Loaded;
}
private void TextBookViewer_Loaded(object sender, RoutedEventArgs e)
{
var img = inkCanvasImage.ImageSource as BitmapSource;
double original_aspect = inkCanvasImage.ImageSource.Width / inkCanvasImage.ImageSource.Height;
double bound_aspect = (double)inkCanvas.ActualWidth / inkCanvas.ActualHeight;
Size size = new Size
{
Width = original_aspect > bound_aspect ? inkCanvas.ActualWidth : (int)Math.Round(inkCanvas.ActualHeight * original_aspect),
Height = original_aspect > bound_aspect ? (int)Math.Round(inkCanvas.ActualWidth / original_aspect) : inkCanvas.ActualHeight
};
var offsetX = (inkCanvas.ActualWidth / 2) - (size.Width / 2);
var offsetY = (inkCanvas.ActualHeight / 2) - (size.Height / 2);
var scaleWidth = (img.PixelWidth) / (size.Width);
var scaleHeight = (img.PixelHeight) / (size.Height);
if(EditControlCollection.Count > 0)
{
foreach(var model in EditControlCollection)
{
var CONTROL_TYPE = model.CustomControlnfo.CONTROL_TYPE;
var WIDTH = model.CustomControlnfo.WIDTH / scaleWidth;
var HEIGHT = model.CustomControlnfo.HEIGHT / scaleHeight;
var X = (model.CustomControlnfo.X / scaleWidth) + offsetX;
var Y = (model.CustomControlnfo.Y / scaleHeight) + offsetY;
var SOURCE = model.CustomControlnfo.SOURCE;
BindableBaseControl childItem = model.EditControl as BindableBaseControl;
switch (CONTROL_TYPE)
{
case "BLANK":
childItem = new AbleControl.BlankBox();
(childItem as AbleControl.BlankBox).DeleteButtonVisibility = Visibility.Hidden;
break;
case "VIDEO":
case "SOUND":
case "IMAGE":
childItem = new AbleControl.MediaBox();
(childItem as AbleControl.MediaBox).MediaSource = SOURCE;
(childItem as AbleControl.MediaBox).MediaType = CONTROL_TYPE;
(childItem as AbleControl.MediaBox).DeleteButtonVisibility = Visibility.Hidden;
break;
}
childItem.Width = WIDTH;
childItem.Height = HEIGHT;
Canvas.SetLeft(childItem, X);
Canvas.SetTop(childItem, Y);
ItemsCanvas.Children.Add(childItem);
}
}
}
private void ClearItemSelected()
{
foreach (var item in ItemsCanvas.Children)
{
if (item.GetType().Equals(typeof(AbleControl.BlankBox)))
{
(item as AbleControl.BlankBox).IsSelected = false;
}
else if (item.GetType().Equals(typeof(AbleControl.MediaBox)))
{
(item as AbleControl.MediaBox).IsSelected = false;
}
}
}
#region 교재 Nagative 처리
public static ImageSource ConvertBitmapToImageSource(System.Drawing.Bitmap bitmap)
{
BitmapImage bitmapImage = new BitmapImage();
using (MemoryStream memory = new MemoryStream())
{
bitmap.Save(memory, ImageFormat.Jpeg);
memory.Position = 0;
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
}
return bitmapImage;
}
public System.Drawing.Bitmap Transform(System.Drawing.Bitmap source)
{
//get a graphics object from the new image
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(source);
// create the negative color matrix
ColorMatrix colorMatrix = new ColorMatrix(new float[][]
{
new float[] {-1, 0, 0, 0, 0},
new float[] {0, -1, 0, 0, 0},
new float[] {0, 0, -1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {1, 1, 1, 0, 1}
});
imageAttributes.SetColorMatrix(colorMatrix);
g.DrawImage(source, new System.Drawing.Rectangle(0, 0, source.Width, source.Height),
0, 0, source.Width, source.Height, System.Drawing.GraphicsUnit.Pixel, imageAttributes);
//dispose the Graphics object
g.Dispose();
return source;
}
#endregion
private void ResetEvent()
{
inkCanvas.RemoveRoutedEventHandlers(InkCanvas.MouseLeftButtonDownEvent);
inkCanvas.RemoveRoutedEventHandlers(InkCanvas.MouseMoveEvent);
inkCanvas.RemoveRoutedEventHandlers(InkCanvas.MouseLeftButtonUpEvent);
}
public void Command(LectureCommnad lectureCommnad)
{
Task.Delay(1);
eventFlag = EventFlag.None;
switch (lectureCommnad)
{
case LectureCommnad.PenMode:
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
break;
case LectureCommnad.MoveMode:
inkCanvas.EditingMode = InkCanvasEditingMode.None;
eventFlag = scaleTransform.ScaleX > 1.0d ? EventFlag.Pan : EventFlag.None;
break;
case LectureCommnad.ZoomMode:
inkCanvas.EditingMode = InkCanvasEditingMode.None;
selectionCanvas.Visibility = Visibility.Visible;
eventFlag = EventFlag.Zoom;
break;
case LectureCommnad.FillMode:
FiilAndReset();
break;
case LectureCommnad.CroppedBlackBoardMode:
eventFlag = EventFlag.Crop;
break;
case LectureCommnad.Nagative:
inkCanvasImage.ImageSource = ConvertBitmapToImageSource(Transform(CurrentTextBook));
break;
}
}
///
/// 교재 확대 취소(1:1 Fill 처리) 및 이벤트 Clear
///
private void FiilAndReset()
{
var scaleAnimation = new DoubleAnimation()
{
From = scaleTransform.ScaleX,
To = 1.0,
Duration = TimeSpan.FromMilliseconds(300),
FillBehavior = FillBehavior.Stop
};
var translateXAnimation = new DoubleAnimation()
{
From = translateTransform.X,
To = 0.0,
Duration = TimeSpan.FromMilliseconds(300),
FillBehavior = FillBehavior.Stop
};
var translateYAnimation = new DoubleAnimation()
{
From = translateTransform.Y,
To = 0.0,
Duration = TimeSpan.FromMilliseconds(300),
FillBehavior = FillBehavior.Stop
};
scaleAnimation.Completed += (s, e) =>
{
scaleTransform.ScaleX = 1.0;
scaleTransform.ScaleY = 1.0;
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, null);
};
translateYAnimation.Completed += (s, e) =>
{
translateTransform.X = 0.0;
translateTransform.Y = 0.0;
translateTransform.BeginAnimation(TranslateTransform.XProperty, null);
translateTransform.BeginAnimation(TranslateTransform.YProperty, null);
};
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
translateTransform.BeginAnimation(TranslateTransform.XProperty, translateXAnimation);
translateTransform.BeginAnimation(TranslateTransform.YProperty, translateYAnimation);
}
#region 교재 확대 처리 이벤트
private void TextBookViewer_MarqueeZoomMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Capture and track the mouse.
isMouseDown = true;
mouseDownPos = e.GetPosition(inkCanvas);
inkCanvas.CaptureMouse();
switch (eventFlag)
{
case EventFlag.Zoom:
case EventFlag.Crop:
// Initial placement of the drag selection box.
Canvas.SetLeft(selectionBox, mouseDownPos.X);
Canvas.SetTop(selectionBox, mouseDownPos.Y);
selectionBox.Width = 0;
selectionBox.Height = 0;
// Make the drag selection box visible.
selectionBox.Visibility = System.Windows.Visibility.Visible;
break;
case EventFlag.Pan:
originTransformPos = new Point(translateTransform.X, translateTransform.Y);
break;
}
}
private void TextBookViewer_MarqueeZoomMouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown)
{
Point mousePos = e.GetPosition(inkCanvas);
switch (eventFlag)
{
case EventFlag.Zoom:
case EventFlag.Crop:
selectionBox.SetValue(Canvas.LeftProperty, Math.Min(mousePos.X, mouseDownPos.X));
selectionBox.SetValue(Canvas.TopProperty, Math.Min(mousePos.Y, mouseDownPos.Y));
selectionBox.Width = Math.Abs(mousePos.X - mouseDownPos.X);
selectionBox.Height = Math.Abs(mousePos.Y - mouseDownPos.Y);
if (selectionBox.Visibility != Visibility.Visible)
selectionBox.Visibility = Visibility.Visible;
Rect selectRect = new Rect(Canvas.GetLeft(selectionBox), Canvas.GetTop(selectionBox), selectionBox.Width, selectionBox.Height);
Dispatcher.Invoke(() =>
{
Point inkCanvasTop = new Point(0, 0);
selectionBoxOutterTop.Rect = new Rect(inkCanvasTop.X, inkCanvasTop.Y, inkCanvas.ActualWidth, selectRect.Top);
selectionBoxOutterLeft.Rect = new Rect(inkCanvasTop.X, inkCanvasTop.Y, selectRect.Left, inkCanvas.ActualHeight);
selectionBoxOutterBottom.Rect = new Rect(inkCanvasTop.X, selectRect.Bottom, inkCanvas.ActualWidth, inkCanvas.ActualHeight);
selectionBoxOutterRight.Rect = new Rect(selectRect.TopRight.X, selectRect.TopRight.Y, inkCanvas.ActualWidth, inkCanvas.ActualHeight);
});
break;
case EventFlag.Pan:
Vector vector = mouseDownPos - mousePos;
if(!vector.Equals(new Vector(0, 0)))
{
translateTransform.X = originTransformPos.X - vector.X;
translateTransform.Y = originTransformPos.Y - vector.Y;
originTransformPos.X = translateTransform.X;
originTransformPos.Y = translateTransform.Y;
}
break;
}
}
}
private void TextBookViewer_MarqueeZoomMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isMouseDown)
{
// Release the mouse capture and stop tracking it.
isMouseDown = false;
inkCanvas.ReleaseMouseCapture();
Rect selectRect = new Rect(Canvas.GetLeft(selectionBox), Canvas.GetTop(selectionBox), selectionBox.Width, selectionBox.Height);
//if (sizeX < 100 || sizeY < 100)
//{
// return;
//}
// Hide the drag selection box.
selectionBox.Visibility = System.Windows.Visibility.Collapsed;
switch(eventFlag)
{
case EventFlag.Crop:
var img = inkCanvasImage.ImageSource as BitmapSource;
double original_aspect = inkCanvasImage.ImageSource.Width / inkCanvasImage.ImageSource.Height;
double bound_aspect = (double)inkCanvas.ActualWidth / inkCanvas.ActualHeight;
Size size = new Size
{
Width = original_aspect > bound_aspect ? inkCanvas.ActualWidth : (int)Math.Round(inkCanvas.ActualHeight * original_aspect),
Height = original_aspect > bound_aspect ? (int)Math.Round(inkCanvas.ActualWidth / original_aspect) : inkCanvas.ActualHeight
};
var offsetX = (inkCanvas.ActualWidth / 2) - (size.Width / 2);
var offsetY = (inkCanvas.ActualHeight / 2) - (size.Height / 2);
var scaleWidth = (img.PixelWidth) / (size.Width);
var scaleHeight = (img.PixelHeight) / (size.Height);
var rcFrom = new Int32Rect()
{
X = (int)((selectRect.X - offsetX) * scaleWidth),
Y = (int)((selectRect.Y - offsetY) * scaleHeight),
Width = (int)(selectRect.Width * scaleWidth),
Height = (int)(selectRect.Height * scaleHeight)
};
rcFrom.X = rcFrom.X < 0 ? 0 : rcFrom.X;
rcFrom.Y = rcFrom.Y < 0 ? 0 : rcFrom.Y;
rcFrom.Width = (rcFrom.X + rcFrom.Width) > img.PixelWidth ? img.PixelWidth - rcFrom.X : rcFrom.Width;
rcFrom.Height = (rcFrom.Y + rcFrom.Height) > img.PixelHeight ? img.PixelHeight - rcFrom.Y : rcFrom.Height;
if (OnCroppedBitmapCompleted != null)
{
CroppedBitmap croppedBitmap = new CroppedBitmap(img, rcFrom);
OnCroppedBitmapCompleted(null, new CroppedBitmapCompleteEventArgs
{
croppedBitmap = croppedBitmap,
SizeX = croppedBitmap.PixelWidth,
SizeY = croppedBitmap.PixelHeight,
SelectWidth = selectRect.Width * scaleWidth,
SelectHeight = selectRect.Height * scaleHeight
});
}
break;
case EventFlag.Zoom:
Point center = new Point(selectRect.Left + (selectRect.Width / 2), selectRect.Top + ((selectRect.Height) / 2));
double scaleX = inkCanvas.ActualWidth / selectRect.Width;
scaleX = Math.Abs(Math.Truncate(scaleX) - scaleX) > 0.5 ? Math.Truncate(scaleX) + 0.5 : Math.Truncate(scaleX);
Point TransPoint = new Point((inkCanvas.ActualWidth / 2) - center.X, (inkCanvas.ActualHeight / 2) - center.Y);
double scaleY = Math.Truncate(inkCanvas.ActualHeight / selectRect.Height);
scaleY = Math.Abs(Math.Truncate(scaleY) - scaleY) > 0.5 ? Math.Truncate(scaleY) + 0.5 : Math.Truncate(scaleY);
double scale = Math.Min(scaleX, scaleY);
scale = scale > 5.0d ? 5.0d : scale;
double absoluteX = center.X * scaleTransform.ScaleX + translateTransform.X;
double absoluteY = center.Y * scaleTransform.ScaleY + translateTransform.Y;
var scaleAnimation = new DoubleAnimation()
{
From = 1,
To = scale,
Duration = TimeSpan.FromMilliseconds(300),
FillBehavior = FillBehavior.Stop
};
scaleAnimation.Completed += (s, e) =>
{
scaleTransform.ScaleX = scale;
scaleTransform.ScaleY = scale;
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, null);
};
var translateXAnimation = new DoubleAnimation()
{
From = translateTransform.X,
To = (absoluteX - center.X * scale) + TransPoint.X,
Duration = TimeSpan.FromMilliseconds(300),
FillBehavior = FillBehavior.Stop
//HandoffBehavior.SnapshotAndReplace
};
translateXAnimation.Completed += (s, e) =>
{
translateTransform.X = (absoluteX - center.X * scale) + TransPoint.X;
translateTransform.BeginAnimation(TranslateTransform.XProperty, null);
if (OnZoomedCompleted != null)
{
OnZoomedCompleted(null, new ZoomedCompleteEventArgs
{
Completed = true
});
}
};
var translateYAnimation = new DoubleAnimation()
{
From = translateTransform.Y,
To = (absoluteY - center.Y * scale) + TransPoint.Y,
Duration = TimeSpan.FromMilliseconds(300),
FillBehavior = FillBehavior.Stop
};
translateYAnimation.Completed += (s, e) =>
{
translateTransform.Y = (absoluteY - center.Y * scale) + TransPoint.Y;
translateTransform.BeginAnimation(TranslateTransform.YProperty, null);
if (OnZoomedCompleted != null)
{
OnZoomedCompleted(null, new ZoomedCompleteEventArgs
{
Completed = true
});
}
};
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
translateTransform.BeginAnimation(TranslateTransform.XProperty, translateXAnimation);
translateTransform.BeginAnimation(TranslateTransform.YProperty, translateYAnimation);
eventFlag = EventFlag.Pan;
//ResetEvent();
//
//inkCanvas.MouseLeftButtonDown += TextBookViewer_PanMouseLeftButtonDown;
//inkCanvas.MouseMove += TextBookViewer_PanMouseMove;
//inkCanvas.MouseLeftButtonUp += TextBookViewer_PanMouseLeftButtonUp;
break;
case EventFlag.Pan:
//inkCanvas.ReleaseMouseCapture();
break;
}
}
}
#endregion
}
}