using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Printing;
using System.Drawing.Printing;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Text.RegularExpressions;
namespace gsview
{
///
/// Interaction logic for PrintControl.xaml
///
///
static class NATIVEWIN
{
public const int IDOK = 1;
public const int IDCANCEL = 2;
public const int DM_OUT_BUFFER = 2;
public const int DM_IN_BUFFER = 8;
public const int DM_IN_PROMPT = 4;
public const int DM_ORIENTATION = 1;
public const int DM_PAPERSIZE = 2;
public const int DM_PAPERLENGTH = 4;
public const int DM_WIDTH = 8;
public const int DMORIENT_PORTRAIT = 1;
public const int DMORIENT_LANDSCAPE = 2;
}
public enum PrintPages_t
{
RANGE = 2,
CURRENT = 1,
ALL = 0
}
public enum PageSubset_t
{
ALL = 0,
ODD = 1,
EVEN = 2
}
public enum PageScale_t
{
NONE = 0,
FIT = 1,
}
public enum Units_t
{
INCHES = 0,
CM = 1
}
public class PrintDiagEventArgs : EventArgs
{
public int m_page;
public PrintDiagEventArgs(int page)
{
m_page = page;
}
}
public class PrintRanges
{
public List ToPrint;
public bool HasEvens;
public bool HasOdds;
public int NumberPages;
public PrintRanges(int number_pages)
{
ToPrint = new List(number_pages);
NumberPages = 0;
HasEvens = false;
HasOdds = false;
}
public void InitRange(Match match)
{
NumberPages = 0;
HasEvens = false;
HasOdds = false;
for (int k = 0; k < ToPrint.Count; k++)
{
if (CheckValue(match, k))
{
NumberPages = NumberPages + 1;
ToPrint[k] = true;
if ((k+1) % 2 != 0)
HasOdds = true;
else
HasEvens = true;
}
else
ToPrint[k] = false;
}
}
private bool CheckValue(Match match, int k)
{
return false;
}
}
public partial class PrintControl : Window
{
private LocalPrintServer m_printServer;
public PrintQueue m_selectedPrinter = null;
String m_status;
PrintPages_t m_pages_setting;
PageSubset_t m_page_subset;
public double m_page_scale;
Units_t m_units;
int m_numpages;
int m_currpage;
PrintCapabilities m_printcap;
public PageSettings m_pagedetails;
TranslateTransform m_trans_pap;
TranslateTransform m_trans_doc;
double m_doc_height;
double m_doc_width;
public bool m_isrotated;
PrintRanges m_range_pages;
public int m_numcopies;
bool m_initdone;
bool m_is64bit;
/* Callback to main to get preview images */
internal delegate bool PrintDiagCallBackPreview(object gsObject, PrintDiagEventArgs info);
internal event PrintDiagCallBackPreview PrintDiagUpdatePreview;
/* Callback to perform printing */
internal delegate void PrintDiagCallBackPrint(object gsObject);
internal event PrintDiagCallBackPrint PrintDiagPrint;
/* Callback to report problems */
internal delegate void PrintDLLProblem(object gsObject, String mess);
internal event PrintDLLProblem PrintDLLProblemMain;
/* Helper for displaying the custom printer dialog settings */
#region DLLInterface
[DllImport("gsprint64.dll", EntryPoint = "ShowPropertiesDialog", CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
private static extern int ShowPropertiesDialog64(IntPtr hwnd, IntPtr printername, bool show_diag );
[DllImport("gsprint32.dll", EntryPoint = "ShowPropertiesDialog", CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
private static extern int ShowPropertiesDialog32(IntPtr hwnd, IntPtr printername, bool show_diag);
#endregion DLLInterface
#region DLLErrorCatch
/* In case the DLL is not found we need to wrap the methods up with
* a try/catch. Also select 32 or 64 bit DLL at this time. This
* C# code is compiled as ANYCPU type */
private int tc_ShowPropertiesDialog(IntPtr hwnd, IntPtr printername, bool show_prop)
{
int code;
try
{
if (m_is64bit)
code = ShowPropertiesDialog64(hwnd, printername, show_prop);
else
code = ShowPropertiesDialog32(hwnd, printername, show_prop);
}
catch (DllNotFoundException)
{
/* DLL not found */
String output = "DllNotFoundException: gsprint DLL not found";
PrintDLLProblemMain(this, output);
return -1;
}
catch (BadImageFormatException)
{
/* Using 32 bit with 64 or vice versa */
String output = "BadImageFormatException: Incorrect gsprint DLL";
PrintDLLProblemMain(this, output);
return -1;
}
return code;
}
#endregion DLLErrorCatch
/* Populate the printers */
private void InitPrinterList()
{
PrintQueueCollection printQueuesOnLocalServer =
m_printServer.GetPrintQueues(new[] {EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections});
this.xaml_selPrinter.ItemsSource = printQueuesOnLocalServer;
if (m_selectedPrinter != null)
{
foreach (PrintQueue pq in printQueuesOnLocalServer)
{
if (pq.FullName == m_selectedPrinter.FullName)
{
this.xaml_selPrinter.SelectedItem = pq;
break;
}
}
}
}
/* Initialize */
public PrintControl(int num_pages, int curr_page)
{
PrinterSettings ps = new PrinterSettings();
this.Closing += new System.ComponentModel.CancelEventHandler(FakeWindowClosing);
InitializeComponent();
m_printServer = new LocalPrintServer();
m_selectedPrinter = LocalPrintServer.GetDefaultPrintQueue();
InitPrinterList();
ps.PrinterName = m_selectedPrinter.FullName;
m_pagedetails = ps.DefaultPageSettings;
xaml_rbAll.IsChecked = true;
m_pages_setting = PrintPages_t.ALL;
m_page_subset = PageSubset_t.ALL;
xaml_Subset.SelectedIndex = (int) m_page_subset;
xaml_autofit.IsChecked = false;
xaml_inches.IsChecked = true;
m_units = Units_t.INCHES;
m_currpage = curr_page;
m_numpages = num_pages;
xaml_pagecount.Text = "1/" + num_pages;
xaml_pageslider.Maximum = num_pages - 1;
m_printcap = m_selectedPrinter.GetPrintCapabilities();
m_trans_pap = new TranslateTransform(0, 0);
m_trans_doc = new TranslateTransform(0, 0);
m_isrotated = false;
/* Data range case */
m_range_pages = new PrintRanges(m_numpages);
m_page_scale = 1.0;
m_numcopies = 1;
m_initdone = false;
m_is64bit = Environment.Is64BitOperatingSystem &&
Environment.Is64BitProcess;
}
void FakeWindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
this.Hide();
}
public void RealWindowClosing()
{
this.Closing -= new System.ComponentModel.CancelEventHandler(FakeWindowClosing);
this.Close();
}
/* Displays and updates the custom printer dialog settings. One can
* either do this with pinvoke of the various commands in winspool or
* go ahead and handle it in our own dll, which is what I decided to
* do. */
private void ShowProperties(object sender, RoutedEventArgs e)
{
PrinterChanged(true);
}
private void PrinterChanged(bool show_prop)
{
if (m_selectedPrinter != null)
{
var ptrNameGC = new GCHandle();
var temp = System.Text.Encoding.UTF8.GetBytes(m_selectedPrinter.FullName.ToCharArray());
ptrNameGC = GCHandle.Alloc(temp, GCHandleType.Pinned);
int res = tc_ShowPropertiesDialog(new WindowInteropHelper(this).Handle, ptrNameGC.AddrOfPinnedObject(), show_prop);
ptrNameGC.Free();
if (res >= 0)
{
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = m_selectedPrinter.FullName;
m_pagedetails = ps.DefaultPageSettings;
UpdateView();
}
}
}
/* Printer selection changed */
private void selPrinterChanged(object sender, SelectionChangedEventArgs e)
{
m_selectedPrinter = this.xaml_selPrinter.SelectedItem as PrintQueue;
GetPrinterStatus();
if (m_initdone)
PrinterChanged(false);
}
/* Printer Status */
private void GetPrinterStatus()
{
if (m_selectedPrinter.IsBusy)
m_status = "Busy";
else if (m_selectedPrinter.IsNotAvailable)
m_status = "Not Available";
else if (m_selectedPrinter.IsOffline)
m_status = "Offline";
else if (m_selectedPrinter.IsOutOfMemory)
m_status = "Out Of Memory";
else if (m_selectedPrinter.IsOutOfPaper)
m_status = "Out Of Paper";
else if (m_selectedPrinter.IsOutputBinFull)
m_status = "Output Bin Full";
else if (m_selectedPrinter.IsPaperJammed)
m_status = "Paper Jam";
else if (m_selectedPrinter.IsPaused)
m_status = "Paused";
else if (m_selectedPrinter.IsPendingDeletion)
m_status = "Paused";
else if (m_selectedPrinter.IsPrinting)
m_status = "Printing";
else if (m_selectedPrinter.IsProcessing)
m_status = "Processing";
else if (m_selectedPrinter.IsWaiting)
m_status = "Waiting";
else if (m_selectedPrinter.IsWarmingUp)
m_status = "Warming Up";
else
m_status = "Ready";
xaml_Status.Text = m_status;
}
private void Subset_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
/* On current page, only All is allowed */
m_page_subset = (PageSubset_t) xaml_Subset.SelectedIndex;
if (m_pages_setting == PrintPages_t.CURRENT &&
m_page_subset != PageSubset_t.ALL)
xaml_Subset.SelectedIndex = (int) PageSubset_t.ALL;
/* Only one page, can't use even */
if (m_pages_setting == PrintPages_t.ALL &&
m_page_subset == PageSubset_t.EVEN &&
m_numpages == 1)
xaml_Subset.SelectedIndex = (int)PageSubset_t.ALL;
}
private void AllPages(object sender, RoutedEventArgs e)
{
xaml_invalid.Visibility = System.Windows.Visibility.Collapsed;
xaml_pageslider.Maximum = m_numpages - 1;
xaml_pageslider.Value = m_currpage;
xaml_pagecount.Text = (m_currpage + 1) + "/" + m_numpages;
m_pages_setting = PrintPages_t.ALL;
}
private void CurrentPage(object sender, RoutedEventArgs e)
{
xaml_invalid.Visibility = System.Windows.Visibility.Collapsed;
m_pages_setting = PrintPages_t.CURRENT;
xaml_pagecount.Text = "1/1";
xaml_pageslider.Maximum = 0;
xaml_pageslider.Value = 0;
PrintDiagEventArgs info = new PrintDiagEventArgs(m_currpage);
PrintDiagUpdatePreview(this, info);
}
private void PageRange(object sender, RoutedEventArgs e)
{
xaml_invalid.Visibility = System.Windows.Visibility.Collapsed;
m_pages_setting = PrintPages_t.RANGE;
}
private void UpdateScaleInfo()
{
/*
if (m_page_scale_type == PageScale_t.NONE)
{
double temp_width_doc = Math.Truncate(m_doc_width * 100.0) / 100.0;
double temp_height_doc = Math.Truncate(m_doc_height * 100.0) / 100.0;
double temp_width_page = m_pagedetails.Bounds.Width / 100;
double temp_height_page = m_pagedetails.Bounds.Height / 100;
if (m_units == Units_t.CM)
{
temp_height_doc = (Math.Truncate(temp_height_doc * 2.54 * 100) / 100.0);
temp_width_doc = (Math.Truncate(temp_width_doc * 2.54 * 100) / 100.0);
temp_height_page = (Math.Truncate(temp_height_page * 2.54 * 100) / 100.0);
temp_width_page = (Math.Truncate(temp_width_page * 2.54 * 100) / 100.0);
}
xaml_pagesize.Text = "Paper:\t\t" + temp_width_page + " x " + temp_height_page;
xaml_docsize.Text = "Document:\t" + temp_width_doc + " x " + temp_height_doc; ;
xaml_pagesize.Visibility = System.Windows.Visibility.Visible;
xaml_docsize.Visibility = System.Windows.Visibility.Visible;
}
else
{
xaml_pagesize.Visibility = System.Windows.Visibility.Collapsed;
xaml_docsize.Visibility = System.Windows.Visibility.Collapsed;
}
* */
}
private void Inches(object sender, RoutedEventArgs e)
{
m_units = Units_t.INCHES;
UpdateUnits();
UpdateScaleInfo();
}
private void Centimeters(object sender, RoutedEventArgs e)
{
m_units = Units_t.CM;
UpdateUnits();
UpdateScaleInfo();
}
public void SetImage(BitmapSource image_in, double doc_height_in,
double doc_width_in)
{
xaml_PreviewImageRect.Visibility = System.Windows.Visibility.Collapsed;
xaml_PreviewGrayRect.Visibility = System.Windows.Visibility.Collapsed;
xaml_PreviewPaper.Visibility = System.Windows.Visibility.Collapsed;
m_doc_width = doc_width_in;
m_doc_height = doc_height_in;
xaml_ImagePreview.ImageSource = image_in;
xaml_ImagePreviewClip.ImageSource = image_in;
UpdateView();
}
private void UpdateView()
{
/* For our display we compute the page size as well as the paper size */
/* The max length sets our scaling of each component */
/* We then determine if any additional scaling is needed or translation
* based upon the settings of m_page_scale_type as well as the autofit
* and scale setting */
double page_height = m_pagedetails.Bounds.Height;
double page_width = m_pagedetails.Bounds.Width;
double doc_height = m_doc_height * 100;
double doc_width = m_doc_width * 100;
bool autofit = (xaml_autofit.IsChecked == true);
bool center;
/* bool center = (xaml_center.IsChecked == true); */
double scale_height;
double scale_width;
double max_scale;
double doc_offset_x = 0;
double doc_offset_y = 0;
double pap_offset_x = 0;
double pap_offset_y = 0;
Rect clip_rect;
center = autofit; /* I may separate these later */
m_page_scale = 1.0;
m_isrotated = false;
if (autofit &&
((m_pagedetails.Bounds.Height > m_pagedetails.Bounds.Width && doc_height < doc_width) ||
(m_pagedetails.Bounds.Height < m_pagedetails.Bounds.Width && doc_height > doc_width)))
{
page_width = m_pagedetails.Bounds.Height;
page_height = m_pagedetails.Bounds.Width;
m_isrotated = true;
}
/* Scale page data if needed. */
if (xaml_autofit.IsChecked == true)
{
scale_height = page_height / doc_height;
scale_width = page_width / doc_width;
max_scale = Math.Min(scale_height, scale_width);
/* Adjust the doc size to fit in the page */
doc_height = doc_height * max_scale;
doc_width = doc_width * max_scale;
m_page_scale = max_scale;
}
/* Now figure out our preview scaling to ensure everything fits
* in the display window */
double max_height = Math.Max(doc_height, page_height);
double max_width = Math.Max(doc_width, page_width);
double max_length = Math.Max(max_height, max_width);
double previewscale = (double)Constants.MAX_PRINT_PREVIEW_LENGTH / max_length;
/* Adjust size of everything */
doc_height = doc_height * previewscale;
doc_width = doc_width * previewscale;
page_height = page_height * previewscale;
page_width = page_width * previewscale;
xaml_PreviewImageRect.Visibility = System.Windows.Visibility.Collapsed;
xaml_PreviewGrayRect.Visibility = System.Windows.Visibility.Collapsed;
xaml_PreviewPaper.Visibility = System.Windows.Visibility.Collapsed;
/* Compute any offsets if needed due to centering */
if (center)
{
if (doc_height > page_height)
pap_offset_y = (doc_height - page_height) / 2.0;
else
doc_offset_y = (page_height - doc_height) / 2.0;
if (doc_width > page_width)
pap_offset_x = (doc_width - page_width) / 2.0;
else
doc_offset_x = (page_width - doc_width) / 2.0;
}
double offset_y = 0;
if (!autofit)
offset_y = doc_height - page_height;
/* See if the paper needs to translate */
if (page_height < doc_height)
m_trans_pap = new TranslateTransform(pap_offset_x, pap_offset_y + offset_y);
else
m_trans_pap = new TranslateTransform(pap_offset_x, pap_offset_y);
/* See if the doc needs to translate */
if (page_height > doc_height)
m_trans_doc = new TranslateTransform(doc_offset_x, doc_offset_y - offset_y);
else
m_trans_doc = new TranslateTransform(doc_offset_x, doc_offset_y);
/* Page black outer rect */
xaml_PreviewPaperOuterRect.RenderTransform = m_trans_pap;
xaml_PreviewPaperOuterRect.Height = page_height;
xaml_PreviewPaperOuterRect.Width = page_width;
xaml_PreviewPaperOuterRect.Visibility = System.Windows.Visibility.Visible;
/* Paper white fill */
xaml_PreviewPaper.RenderTransform = m_trans_pap;
xaml_PreviewPaper.Height = page_height;
xaml_PreviewPaper.Width = page_width;
xaml_PreviewPaper.Visibility = System.Windows.Visibility.Visible;
/* The image */
xaml_PreviewImageRect.RenderTransform = m_trans_doc;
xaml_PreviewImageRect.Height = doc_height;
xaml_PreviewImageRect.Width = doc_width;
xaml_PreviewImageRect.Visibility = System.Windows.Visibility.Visible;
/* The gray fill (not visible) */
xaml_PreviewGrayRect.RenderTransform = m_trans_doc;
xaml_PreviewGrayRect.Height = doc_height;
xaml_PreviewGrayRect.Width = doc_width;
xaml_PreviewGrayRect.Visibility = System.Windows.Visibility.Visible;
/* The visible portion */
xaml_PreviewImageRectClip.RenderTransform = m_trans_doc;
xaml_PreviewImageRectClip.Height = doc_height;
xaml_PreviewImageRectClip.Width = doc_width;
clip_rect = new Rect(pap_offset_x, pap_offset_y + offset_y, page_width, page_height);
xaml_ImagePreviewClipGeom.Rect = clip_rect;
xaml_PreviewImageRectClip.Visibility = System.Windows.Visibility.Visible;
UpdateSizes();
UpdateScaleInfo();
m_initdone = true;
}
private void PageSelect_DragCompleted(object sender, MouseButtonEventArgs e)
{
if (m_pages_setting == PrintPages_t.CURRENT)
return;
/* Get the current page view */
int page = (int) xaml_pageslider.Value;
PrintDiagEventArgs info = new PrintDiagEventArgs(page);
PrintDiagUpdatePreview(this, info);
page = page + 1;
xaml_pagecount.Text = page + "/" + m_numpages;
}
private void AdjustPageSize()
{
m_printcap = m_selectedPrinter.GetPrintCapabilities();
}
private void UpdateSizes()
{
xaml_TopArrowCanvas.RenderTransform = new TranslateTransform(m_trans_pap.X, 0);
xaml_topsize.X2 = xaml_PreviewPaper.Width;
xaml_toprighttoparrow.X1 = xaml_PreviewPaper.Width - 7;
xaml_toprighttoparrow.X2 = xaml_PreviewPaper.Width;
xaml_toprightbottomarrow.X1 = xaml_PreviewPaper.Width - 7;
xaml_toprightbottomarrow.X2 = xaml_PreviewPaper.Width;
xaml_LeftArrowCanvas.RenderTransform = new TranslateTransform(0, m_trans_pap.Y);
xaml_leftsize.Y2 = xaml_PreviewPaper.Height;
xaml_leftbottomleft.Y1 = xaml_PreviewPaper.Height - 7;
xaml_leftbottomleft.Y2 = xaml_PreviewPaper.Height;
xaml_leftbottomright.Y1 = xaml_PreviewPaper.Height - 7;
xaml_leftbottomright.Y2 = xaml_PreviewPaper.Height;
xaml_LeftArrowCanvas.Visibility = System.Windows.Visibility.Visible;
xaml_TopArrowCanvas.Visibility = System.Windows.Visibility.Visible;
UpdateUnits();
}
private void UpdateUnits()
{
double valHeight = m_pagedetails.Bounds.Height;
double valWidth = m_pagedetails.Bounds.Width;
if (m_units == Units_t.INCHES)
{
if (m_isrotated)
{
xaml_topsizevalue.Text = (Math.Truncate(valHeight) / 100.0).ToString();
xaml_leftsizevalue.Text = (Math.Truncate(valWidth) / 100.0).ToString();
}
else
{
xaml_leftsizevalue.Text = (Math.Truncate(valHeight) / 100.0).ToString();
xaml_topsizevalue.Text = (Math.Truncate(valWidth) / 100.0).ToString();
}
}
else
{
if (m_isrotated)
{
xaml_topsizevalue.Text = (Math.Truncate(valHeight * 2.54) / 100.0).ToString();
xaml_leftsizevalue.Text = (Math.Truncate(valWidth * 2.54) / 100.0).ToString();
}
else
{
xaml_leftsizevalue.Text = (Math.Truncate(valHeight * 2.54) / 100.0).ToString();
xaml_topsizevalue.Text = (Math.Truncate(valWidth * 2.54) / 100.0).ToString();
}
}
}
private void PageNumberEnter(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return)
{
e.Handled = true;
string desired_page = xaml_pagerange.Text;
Regex rangePattern = new Regex(@"^\s*\d+\s*(\-\s*\d+\s*)?(\,\s*\d+\s*(\-\s*\d+\s*)?)*$");
Match m = rangePattern.Match(desired_page);
if (!m.Success)
xaml_invalid.Visibility = System.Windows.Visibility.Visible;
else
{
xaml_invalid.Visibility = System.Windows.Visibility.Collapsed;
}
}
}
private void ClickOK(object sender, RoutedEventArgs e)
{
PrintDiagPrint(this);
this.Hide();
}
private void ClickCancel(object sender, RoutedEventArgs e)
{
this.Hide();
}
private void xaml_Copies_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
{
m_numcopies = (int) e.NewValue;
}
private void AutoFit_Checked(object sender, RoutedEventArgs e)
{
UpdateView();
}
private void AutoFit_Unchecked(object sender, RoutedEventArgs e)
{
UpdateView();
}
}
}