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 { /// <summary> /// Interaction logic for PrintControl.xaml /// </summary> /// 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<bool> ToPrint; public bool HasEvens; public bool HasOdds; public int NumberPages; public PrintRanges(int number_pages) { ToPrint = new List<bool>(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<double> e) { m_numcopies = (int) e.NewValue; } private void AutoFit_Checked(object sender, RoutedEventArgs e) { UpdateView(); } private void AutoFit_Unchecked(object sender, RoutedEventArgs e) { UpdateView(); } } }