From f24f164f25b66df32d7e584ba9993c1519386aac Mon Sep 17 00:00:00 2001 From: Michael Vrhel Date: Tue, 20 Jan 2015 11:37:59 -0800 Subject: Rework of gsview printing with addition of new Print control dialog This adds an additional project (gsprint.vxcproj) which will do the necessary native calls to bring up the custom print dialog for the output device. We can then obtain the settings and make the appropriate page size adjustments in creating our xps content. --- platform/windows/gsprint.vcxproj | 164 +++++++ platform/windows/gsprint/dllmain.cpp | 19 + platform/windows/gsprint/gsprint.cpp | 73 +++ platform/windows/gsprint/gsprint.h | 12 + platform/windows/gsview/MainWindow.xaml.cs | 164 ++++++- platform/windows/gsview/PrintControl.xaml | 247 ++++++++++ platform/windows/gsview/PrintControl.xaml.cs | 697 +++++++++++++++++++++++++++ platform/windows/gsview/ghostsharp.cs | 17 +- platform/windows/gsview/gsprint.cs | 315 +++++++++++- platform/windows/gsview/gsview.csproj | 7 + platform/windows/mupdf.sln | 65 ++- 11 files changed, 1739 insertions(+), 41 deletions(-) create mode 100644 platform/windows/gsprint.vcxproj create mode 100644 platform/windows/gsprint/dllmain.cpp create mode 100644 platform/windows/gsprint/gsprint.cpp create mode 100644 platform/windows/gsprint/gsprint.h create mode 100644 platform/windows/gsview/PrintControl.xaml create mode 100644 platform/windows/gsview/PrintControl.xaml.cs diff --git a/platform/windows/gsprint.vcxproj b/platform/windows/gsprint.vcxproj new file mode 100644 index 00000000..c191599d --- /dev/null +++ b/platform/windows/gsprint.vcxproj @@ -0,0 +1,164 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {09FE8E75-9952-44E7-95F8-E8D74707FBA1} + Win32Proj + gsprint + + + + DynamicLibrary + true + v120 + Unicode + + + DynamicLibrary + true + v120 + Unicode + + + DynamicLibrary + false + v120 + true + Unicode + + + DynamicLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\gsview\bin\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(ProjectName)32 + + + true + $(SolutionDir)\gsview\bin\$(Configuration)\ + $(ProjectName)64 + + + false + $(ProjectName)32 + $(SolutionDir)\gsview\bin\$(Configuration)\ + $(Platform)\$(Configuration)\ + + + false + $(SolutionDir)\gsview\bin\$(Configuration)\ + $(ProjectName)64 + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;GSPRINT_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;GSPRINT_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;GSPRINT_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;GSPRINT_EXPORTS;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platform/windows/gsprint/dllmain.cpp b/platform/windows/gsprint/dllmain.cpp new file mode 100644 index 00000000..bfaa6519 --- /dev/null +++ b/platform/windows/gsprint/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/platform/windows/gsprint/gsprint.cpp b/platform/windows/gsprint/gsprint.cpp new file mode 100644 index 00000000..813364a8 --- /dev/null +++ b/platform/windows/gsprint/gsprint.cpp @@ -0,0 +1,73 @@ +// gsprint.cpp : Defines the exported functions for the DLL application. +// +#include "gsprint.h" +#include "stdlib.h" + +#define FAIL -1 + +/* Code to handle the special device properties window as well as make sure + * that the values are maintained when we leave */ +SYMBOL_DECLSPEC int __stdcall ShowPropertiesDialog(void *hptr, void *printername, bool show_win) +{ + HWND hWnd = (HWND)hptr; + HANDLE hPrinter = NULL; + LPDEVMODE pDevMode; + DWORD dwNeeded, dwRet; + wchar_t *output = NULL; + + int lenA = lstrlenA((char*)printername); + int lenW = ::MultiByteToWideChar(CP_ACP, 0, (char*)printername, lenA, NULL, 0); + if (lenW > 0) + { + output = new wchar_t[lenW + 1]; + if (output == NULL) + return -1; + ::MultiByteToWideChar(CP_ACP, 0, (char*)printername, lenA, output, lenW); + output[lenW] = 0; + } + else + return FAIL; + + if (!OpenPrinter(output, &hPrinter, NULL)) + { + free(output); + return FAIL; + } + + /* First get the size needed */ + dwNeeded = DocumentProperties(hWnd, hPrinter, output, NULL, NULL, 0); + pDevMode = (LPDEVMODE)malloc(dwNeeded); + if (pDevMode == NULL) + { + free(output); + ClosePrinter(hPrinter); + return FAIL; + } + + /* Now actually get the DEVMODE data. DM_IN_PROMPT brings up the window. + * DM_OUT_BUFFER ensures that we get the values that have been set */ + DWORD fMode = DM_OUT_BUFFER; + if (show_win) + fMode = fMode | DM_IN_PROMPT; + + dwRet = DocumentProperties(hWnd, hPrinter, output, pDevMode, NULL, fMode); + if (dwRet != IDOK) + { + free(output); + ClosePrinter(hPrinter); + free(pDevMode); + return FAIL; + } + + /* This is the secret to ensure that the DEVMODE settings are saved. Fun + * finding this bit of information in the MS literature */ + PRINTER_INFO_9 new_info; + new_info.pDevMode = pDevMode; + SetPrinter(hPrinter, 9, (LPBYTE)&new_info, 0); + + /* Clean up */ + free(pDevMode); + free(output); + ClosePrinter(hPrinter); + return 0; +} diff --git a/platform/windows/gsprint/gsprint.h b/platform/windows/gsprint/gsprint.h new file mode 100644 index 00000000..cfc2c7b3 --- /dev/null +++ b/platform/windows/gsprint/gsprint.h @@ -0,0 +1,12 @@ +#include +#include + +#ifdef __cplusplus +#define EXTERNC extern "C" +#else +#define EXTERNC +#endif + +#define SYMBOL_DECLSPEC __declspec(dllexport) + +EXTERN_C SYMBOL_DECLSPEC int __stdcall ShowPropertiesDialog(void *ctx, void *printername, bool show_win); diff --git a/platform/windows/gsview/MainWindow.xaml.cs b/platform/windows/gsview/MainWindow.xaml.cs index 6e6ee855..fd26a50b 100644 --- a/platform/windows/gsview/MainWindow.xaml.cs +++ b/platform/windows/gsview/MainWindow.xaml.cs @@ -153,6 +153,7 @@ static class Constants public const int SCROLL_EDGE_BUFFER = 90; public const int VERT_SCROLL_STEP = 48; public const int PAGE_MARGIN = 1; + public const int MAX_PRINT_PREVIEW_LENGTH = 250; } public static class DocumentTypes @@ -205,6 +206,15 @@ namespace gsview public int num_rects; } + public struct printPreviewPage_t + { + public Byte[] bitmap; + public int width; + public int height; + public double width_inches; + public double height_inches; + } + public struct textSelectInfo_t { public int pagenum; @@ -282,6 +292,7 @@ namespace gsview List m_thumbnails; List> m_page_link_list = null; IList m_text_list; + DocPage m_PrintPreviewPage; public List m_lineptrs = null; public List m_textptrs = null; List m_textset = null; @@ -308,12 +319,14 @@ namespace gsview Convert m_convertwin; PageExtractSave m_extractwin; Password m_password = null; + PrintControl m_printcontrol = null; String m_currpassword = null; BackgroundWorker m_thumbworker = null; BackgroundWorker m_textsearch = null; BackgroundWorker m_linksearch = null; BackgroundWorker m_openfile = null; BackgroundWorker m_initrender = null; + BackgroundWorker m_printerpreview = null; BackgroundWorker m_copytext = null; String m_document_type; Info m_infowindow; @@ -349,6 +362,7 @@ namespace gsview { m_docPages = new Pages(); m_thumbnails = new List(); + m_PrintPreviewPage = new DocPage(); m_lineptrs = new List(); m_textptrs = new List(); m_textset = new List(); @@ -426,6 +440,8 @@ namespace gsview m_gsoutput.RealWindowClosing(); if (m_outputintents != null) m_outputintents.RealWindowClosing(); + if (m_printcontrol != null) + m_printcontrol.RealWindowClosing(); } else { @@ -433,6 +449,8 @@ namespace gsview m_gsoutput.Hide(); if (m_outputintents != null) m_outputintents.Hide(); + if (m_printcontrol != null) + m_printcontrol.Hide(); } } @@ -707,6 +725,12 @@ namespace gsview if (m_password != null && m_password.IsActive) m_password.Close(); + if (m_printcontrol != null && m_printcontrol.IsActive) + { + m_printcontrol.Close(); + m_printcontrol = null; + } + if (m_infowindow != null && m_infowindow.IsActive) m_infowindow.Close(); @@ -1743,47 +1767,40 @@ namespace gsview if (!m_file_open) return; - /* If file is already xps then gs need not do this */ - if (!m_isXPS) + if (m_printcontrol == null) { - xaml_DistillProgress.Value = 0; - if (m_ghostscript.CreateXPS(m_currfile, Constants.DEFAULT_GS_RES, m_num_pages) == gsStatus.GS_BUSY) - { - ShowMessage(NotifyType_t.MESS_STATUS, "GS currently busy"); - return; - } - else - { - /* Right now this is not possible to cancel due to the way - * that gs is run for xpswrite from pdf */ - xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed; - xaml_DistillName.Text = "Convert to XPS"; - xaml_DistillName.FontWeight = FontWeights.Bold; - xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; - } + m_printcontrol = new PrintControl(m_num_pages, m_currpage); + m_printcontrol.PrintDiagUpdatePreview += new PrintControl.PrintDiagCallBackPreview(PrintDiagUpdatePreview); + m_printcontrol.PrintDiagPrint += new PrintControl.PrintDiagCallBackPrint(PrintDiagPrint); + m_printcontrol.PrintDLLProblemMain += new PrintControl.PrintDLLProblem(gsDLL); + m_printcontrol.Activate(); + m_printcontrol.Show(); /* Makes it modal */ + PrintDiagEventArgs args = new PrintDiagEventArgs(0); + PrintDiagUpdatePreview(null, args); } else - PrintXPS(m_currfile); + m_printcontrol.Show(); + return; } private void PrintXPS(String file) { gsprint ghostprint = new gsprint(); - System.Windows.Controls.PrintDialog pDialog = ghostprint.GetPrintDialog(); - if (pDialog == null) - return; /* We have to create the XPS document on a different thread */ XpsDocument xpsDocument = new XpsDocument(file, FileAccess.Read); FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence(); - PrintQueue printQueue = pDialog.PrintQueue; + System.Windows.Size temp = new Size(200, 200); + fixedDocSeq.DocumentPaginator.PageSize = temp; + + PrintQueue printq = m_printcontrol.m_selectedPrinter; m_ghostprint = ghostprint; xaml_PrintGrid.Visibility = System.Windows.Visibility.Visible; xaml_PrintProgress.Value = 0; - ghostprint.Print(printQueue, fixedDocSeq); + ghostprint.Print(printq, fixedDocSeq, m_printcontrol); } private void PrintProgress(object printHelper, gsPrintEventArgs Information) @@ -4902,5 +4919,106 @@ namespace gsview m_showannot = false; RenderRange(m_currpage, false, zoom_t.NO_ZOOM, 0); } + + /* Print preview rendering and control */ + private void RenderPrintPreview(object sender, DoWorkEventArgs e) + { + BackgroundWorker worker = sender as BackgroundWorker; + List genericlist = e.Argument as List; + int k = (int)genericlist[0]; + int desiredMax = Constants.MAX_PRINT_PREVIEW_LENGTH; + + Point ras_size; + double scale_factor = 1.0; + Byte[] bitmap; + BlocksText charlist; + status_t code; + Annotate_t annot; + + if (ComputePageSize(k, scale_factor, out ras_size) == status_t.S_ISOK) + { + /* Adjust the scale factor to ensure max length is set as desired */ + int maxSize = Math.Max((int)ras_size.X, (int)ras_size.Y); + scale_factor = (double)desiredMax / (double)maxSize; + ComputePageSize(k, scale_factor, out ras_size); + printPreviewPage_t result; + + try + { + bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4]; + code = (status_t)mu_doc.RenderPage(k, bitmap, (int)ras_size.X, + (int)ras_size.Y, scale_factor, false, true, + false, out charlist, m_showannot, out annot); + result.width = (int)ras_size.X; + result.height = (int)ras_size.Y; + result.bitmap = bitmap; + ComputePageSize(k, 1.0, out ras_size); + result.height_inches = ras_size.Y / 72.0; + result.width_inches = ras_size.X / 72.0; + e.Result = result; + } + catch (OutOfMemoryException em) + { + Console.WriteLine("Memory allocation failed print preview page " + k + em.Message + "\n"); + } + } + } + + private void RenderPrintPreviewCompleted(object sender, RunWorkerCompletedEventArgs e) + { + BitmapSource BitMapSrc; + printPreviewPage_t Result = (printPreviewPage_t)e.Result; + + int stride = Result.width * 4; + BitMapSrc = BitmapSource.Create(Result.width, Result.height, + 72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, Result.bitmap, stride); + + m_printcontrol.SetImage(BitMapSrc, Result.height_inches, Result.width_inches); + } + + private bool PrintDiagUpdatePreview(object PrintDiag, PrintDiagEventArgs args) + { + try + { + m_printerpreview = new BackgroundWorker(); + m_printerpreview.WorkerReportsProgress = false; + m_printerpreview.WorkerSupportsCancellation = false; + m_printerpreview.DoWork += new DoWorkEventHandler(RenderPrintPreview); + m_printerpreview.RunWorkerCompleted += new RunWorkerCompletedEventHandler(RenderPrintPreviewCompleted); + var arguments = new List(); + arguments.Add(args.m_page); + m_printerpreview.RunWorkerAsync(arguments); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during printpreview render\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + return true; + } + + private void PrintDiagPrint(object PrintDiag) + { + + /* If file is already xps then gs need not do this */ + if (!m_isXPS) + { + xaml_DistillProgress.Value = 0; + if (m_ghostscript.CreateXPS(m_currfile, Constants.DEFAULT_GS_RES, m_num_pages, m_printcontrol) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS currently busy"); + return; + } + else + { + xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed; + xaml_DistillName.Text = "Convert to XPS"; + xaml_DistillName.FontWeight = FontWeights.Bold; + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; + } + } + else + PrintXPS(m_currfile); + } } } \ No newline at end of file diff --git a/platform/windows/gsview/PrintControl.xaml b/platform/windows/gsview/PrintControl.xaml new file mode 100644 index 00000000..8b9c30ae --- /dev/null +++ b/platform/windows/gsview/PrintControl.xaml @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +