From e3cd64f5b9db724368658b84f91027e7b53fe48a Mon Sep 17 00:00:00 2001 From: Michael Vrhel Date: Thu, 24 Apr 2014 22:58:57 -0700 Subject: Addition of support to use mupdf clean to allow page extraction Also support added to include mupdf devices in the output conversions. --- platform/winrt/gsview/Convert.xaml | 13 +- platform/winrt/gsview/Convert.xaml.cs | 31 +++ platform/winrt/gsview/MainWindow.xaml | 53 +++-- platform/winrt/gsview/MainWindow.xaml.cs | 290 ++++++++++++++++++-------- platform/winrt/gsview/PageExtractSave.xaml | 59 ++++++ platform/winrt/gsview/PageExtractSave.xaml.cs | 214 +++++++++++++++++++ platform/winrt/gsview/ghostsharp.cs | 11 +- platform/winrt/gsview/gsview.csproj | 7 + platform/winrt/gsview/mudocument.cs | 240 +++++++++++++++++++++ platform/winrt/libmupdf_winRT.vcxproj | 2 +- platform/winrt/libmupdf_winRT.vcxproj.filters | 6 +- platform/winrt/mupdfnet/mupdfnet.cpp | 92 ++++++++ platform/winrt/mupdfnet/mupdfnet.h | 9 +- platform/winrt/mupdfwinrt/muctx.cpp | 101 ++++++++- platform/winrt/mupdfwinrt/muctx.h | 6 + 15 files changed, 1022 insertions(+), 112 deletions(-) create mode 100644 platform/winrt/gsview/PageExtractSave.xaml create mode 100644 platform/winrt/gsview/PageExtractSave.xaml.cs (limited to 'platform') diff --git a/platform/winrt/gsview/Convert.xaml b/platform/winrt/gsview/Convert.xaml index eb8d4d72..73fcd488 100644 --- a/platform/winrt/gsview/Convert.xaml +++ b/platform/winrt/gsview/Convert.xaml @@ -1,7 +1,7 @@  + Title="Convert Pages" Height="270.96" Width="419.424"> @@ -55,8 +55,10 @@ + + - + @@ -103,9 +105,14 @@ - Options: + GhostScript Options: + + MuPDF Resolution: + + diff --git a/platform/winrt/gsview/Convert.xaml.cs b/platform/winrt/gsview/Convert.xaml.cs index 6c33eb1a..9b2d5f66 100644 --- a/platform/winrt/gsview/Convert.xaml.cs +++ b/platform/winrt/gsview/Convert.xaml.cs @@ -13,6 +13,7 @@ using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.ComponentModel; using System.Collections.ObjectModel; +using System.Text.RegularExpressions; namespace gsview { @@ -24,12 +25,24 @@ namespace gsview internal set; } + public gsDevice_t DeviceType + { + get; + internal set; + } + public bool SupportsMultiPage { get; internal set; } + public bool MuPDFDevice + { + get; + internal set; + } + public event PropertyChangedEventHandler PropertyChanged; public void PageRefresh() @@ -67,6 +80,7 @@ namespace gsview if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Page")); + PropertyChanged(this, new PropertyChangedEventArgs("PageString")); } } }; @@ -100,10 +114,15 @@ namespace gsview { Device device_t = new Device(); device_t.DeviceName = Enum.GetName(typeof(gsDevice_t), device); + device_t.DeviceType = device; if (device > gsDevice_t.psdrgb) device_t.SupportsMultiPage = true; else device_t.SupportsMultiPage = false; + if (device < gsDevice_t.bmp16) + device_t.MuPDFDevice = true; + else + device_t.MuPDFDevice = false; GSDevices.Add(device_t); } } @@ -180,5 +199,17 @@ namespace gsview (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = false; } } + + /* Allow only numbers */ + private void PreviewInput(object sender, TextCompositionEventArgs e) + { + e.Handled = !IsTextAllowed(e.Text); + } + + private static bool IsTextAllowed(string text) + { + Regex regex = new Regex("[^0-9]+"); + return !regex.IsMatch(text); + } } } diff --git a/platform/winrt/gsview/MainWindow.xaml b/platform/winrt/gsview/MainWindow.xaml index cfd02b29..7307619e 100644 --- a/platform/winrt/gsview/MainWindow.xaml +++ b/platform/winrt/gsview/MainWindow.xaml @@ -1,7 +1,7 @@  + Title="gsview" Height="850" Width="714" UseLayoutRounding="True" > @@ -80,12 +80,6 @@ - @@ -139,6 +133,7 @@ + @@ -150,13 +145,9 @@ - - - - - + @@ -182,7 +173,7 @@ - + @@ -198,7 +189,11 @@ - + + + + + @@ -231,7 +226,6 @@ - @@ -575,7 +569,34 @@ --> - + + + + + + + + + MuPDF Converting Document + + + + diff --git a/platform/winrt/gsview/MainWindow.xaml.cs b/platform/winrt/gsview/MainWindow.xaml.cs index d8dee6ef..9c0173fe 100644 --- a/platform/winrt/gsview/MainWindow.xaml.cs +++ b/platform/winrt/gsview/MainWindow.xaml.cs @@ -88,11 +88,10 @@ public enum Save_Type_t PCLXL, XPS, SVG, - PCLBitmap, - PNG, - PWG, - PNM, - TEXT + TEXT, + HTML, + XML, + LINEAR_PDF } public enum Extract_Type_t @@ -212,7 +211,9 @@ namespace gsview bool m_isXPS; gsOutput m_gsoutput; Convert m_convertwin; + PageExtractSave m_extractwin; Password m_password = null; + String m_currpassword = null; BackgroundWorker m_thumbworker = null; BackgroundWorker m_textsearch = null; BackgroundWorker m_linksearch = null; @@ -253,6 +254,7 @@ namespace gsview m_outputintents.Activate(); m_ghostscript.gsIOUpdateMain += new ghostsharp.gsIOCallBackMain(gsIO); m_convertwin = null; + m_extractwin = null; m_selection = null; xaml_ZoomSlider.AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(ZoomReleased), true); @@ -349,6 +351,7 @@ namespace gsview ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); } status_t result = mu_doc.Initialize(); + mu_doc.mupdfUpdateMain += new mudocument.mupdfCallBackMain(mupdfUpdate); if (result != status_t.S_ISOK) { @@ -372,6 +375,7 @@ namespace gsview m_doscroll = false; m_intxtselect = false; m_textselected = false; + m_currpassword = null; return result; } @@ -495,7 +499,10 @@ namespace gsview { DisabletoPDF(); m_isXPS = true; + xaml_Extract.IsEnabled = false; } + else + xaml_Extract.IsEnabled = true; OpenFile2(dlg.FileName); } } @@ -944,6 +951,41 @@ namespace gsview m_gsoutput.Update(mess, len); } + private void mupdfUpdate(object muObject, muPDFEventArgs asyncInformation) + { + if (asyncInformation.Completed) + { + xaml_MuPDFProgress.Value = 100; + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Collapsed; + if (asyncInformation.Params.result == GS_Result_t.gsFAILED) + { + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF failed to convert document"); + } + MuPDFResult(asyncInformation.Params); + } + else + { + this.xaml_MuPDFProgress.Value = asyncInformation.Progress; + } + } + + /* MuPDF Result*/ + public void MuPDFResult(ConvertParams_t gs_result) + { + if (gs_result.result == GS_Result_t.gsCANCELLED) + { + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Collapsed; + return; + } + if (gs_result.result == GS_Result_t.gsFAILED) + { + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Collapsed; + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF Failed Conversion"); + return; + } + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF Completed Conversion"); + } + private void gsProgress(object gsObject, gsEventArgs asyncInformation) { if (asyncInformation.Completed) @@ -1072,6 +1114,12 @@ namespace gsview } } + private void CancelMuPDFClick(object sender, RoutedEventArgs e) + { + xaml_CancelMuPDF.IsEnabled = false; + mu_doc.Cancel(); + } + private void CancelDistillClick(object sender, RoutedEventArgs e) { xaml_CancelDistill.IsEnabled = false; @@ -1108,13 +1156,20 @@ namespace gsview private void ConvertReturn(object sender) { - if (m_ghostscript.GetStatus() != gsStatus.GS_READY) + Device device = (Device)m_convertwin.xaml_DeviceList.SelectedItem; + if (device == null) + { + ShowMessage(NotifyType_t.MESS_STATUS, "No Device Selected"); + return; + } + + if (m_ghostscript.GetStatus() != gsStatus.GS_READY && + !device.MuPDFDevice) { ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); return; } - Device device = (Device)m_convertwin.xaml_DeviceList.SelectedItem; System.Collections.IList pages = m_convertwin.xaml_PageList.SelectedItems; System.Collections.IList pages_selected = null; String options = m_convertwin.xaml_options.Text; @@ -1129,64 +1184,146 @@ namespace gsview return; } - if (device == null) - { - ShowMessage(NotifyType_t.MESS_STATUS, "No Device Selected"); - return; - } - /* Get a filename */ SaveFileDialog dlg = new SaveFileDialog(); dlg.Filter = "All files (*.*)|*.*"; dlg.FilterIndex = 1; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) { - if (!device.SupportsMultiPage && m_num_pages > 1) - multi_page_needed = true; - - if (pages.Count != m_num_pages) + if (device.MuPDFDevice) { - /* We may need to go through page by page. Determine if - * selection of pages is continuous. This is done by - * looking at the first one in the list and the last one - * in the list and checking the length */ - SelectPage lastpage = (SelectPage)pages[pages.Count - 1]; - SelectPage firstpage = (SelectPage)pages[0]; - int temp = lastpage.Page - firstpage.Page + 1; - if (temp == pages.Count) + /* Allow only one of these as a time */ + pages_selected = pages; + var val = m_convertwin.xaml_resolution.Text; + if (val.Length > 0) { - /* Pages are contiguous. Add first and last page - * as command line option */ - options = options + " -dFirstPage=" + firstpage.Page + " -dLastPage=" + lastpage.Page; - first_page = firstpage.Page; - last_page = lastpage.Page; + bool isok = true; + int num = resolution; + try + { + num = System.Convert.ToInt32(val); + } + catch (FormatException e) + { + isok = false; + Console.WriteLine("Input string is not a sequence of digits."); + } + catch (OverflowException e) + { + isok = false; + Console.WriteLine("The number cannot fit in an Int32."); + } + if (isok && num > 0) + resolution = num; } - else + + if (mu_doc.ConvertSave(device.DeviceType, dlg.FileName, + pages.Count, pages_selected, resolution) == gsStatus.GS_BUSY) { - /* Pages are not continguous. We will do this page - * by page.*/ - pages_selected = pages; - multi_page_needed = true; /* need to put in separate outputs */ + ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF conversion busy"); + return; } + xaml_CancelMuPDF.Visibility = System.Windows.Visibility.Visible; + xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Visible; } - xaml_DistillProgress.Value = 0; - if (m_ghostscript.Convert(m_currfile, options, - device.DeviceName, dlg.FileName, pages.Count, resolution, - multi_page_needed, pages_selected, first_page, last_page, - null, null) == gsStatus.GS_BUSY) + else { - ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); - return; + if (!device.SupportsMultiPage && m_num_pages > 1) + multi_page_needed = true; + + if (pages.Count != m_num_pages) + { + /* We may need to go through page by page. Determine if + * selection of pages is continuous. This is done by + * looking at the first one in the list and the last one + * in the list and checking the length */ + SelectPage lastpage = (SelectPage)pages[pages.Count - 1]; + SelectPage firstpage = (SelectPage)pages[0]; + int temp = lastpage.Page - firstpage.Page + 1; + if (temp == pages.Count) + { + /* Pages are contiguous. Add first and last page + * as command line option */ + options = options + " -dFirstPage=" + firstpage.Page + " -dLastPage=" + lastpage.Page; + first_page = firstpage.Page; + last_page = lastpage.Page; + } + else + { + /* Pages are not continguous. We will do this page + * by page.*/ + pages_selected = pages; + multi_page_needed = true; /* need to put in separate outputs */ + } + } + xaml_DistillProgress.Value = 0; + if (m_ghostscript.Convert(m_currfile, options, + device.DeviceName, dlg.FileName, pages.Count, resolution, + multi_page_needed, pages_selected, first_page, last_page, + null, null) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS busy"); + return; + } + xaml_DistillName.Text = "GS Converting Document"; + xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed; + xaml_DistillName.FontWeight = FontWeights.Bold; + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; } - xaml_DistillName.Text = "GS Converting Document"; - xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed; - xaml_DistillName.FontWeight = FontWeights.Bold; - xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; m_convertwin.Close(); } return; } + private void ExtractPages(object sender, RoutedEventArgs e) + { + if (!m_init_done || m_isXPS) + return; + + if (m_extractwin == null || !m_extractwin.IsActive) + { + m_extractwin = new PageExtractSave(m_num_pages); + m_extractwin.ExtractMain += new PageExtractSave.ExtractCallBackMain(ExtractReturn); + m_extractwin.Activate(); + m_extractwin.Show(); + } + } + + private void ExtractReturn(object sender) + { + if (m_extractwin.xaml_PageList.SelectedItems.Count == 0) + { + ShowMessage(NotifyType_t.MESS_STATUS, "No Pages Selected"); + return; + } + + /* Go through the actual list not the selected items list. The + * selected items list contains them in the order that the were + * selected not the order graphically shown */ + List pages = new List(m_extractwin.xaml_PageList.SelectedItems.Count); + + for (int kk = 0; kk < m_extractwin.xaml_PageList.Items.Count; kk++) + { + var item = (m_extractwin.xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk)) as System.Windows.Controls.ListViewItem; + if (item.IsSelected == true) + { + pages.Add((SelectPage) m_extractwin.Pages[kk]); + } + } + + /* Get a filename */ + SaveFileDialog dlg = new SaveFileDialog(); + dlg.Filter = "All files (*.pdf)|*.pdf"; + dlg.FilterIndex = 1; + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + mu_doc.PDFExtract(m_currfile, dlg.FileName, m_currpassword, m_currpassword != null, + false, pages.Count, pages); + m_extractwin.Close(); + } + return; + } + private void GetPassword() { if (m_password == null) @@ -1202,6 +1339,7 @@ namespace gsview { if (mu_doc.ApplyPassword(m_password.xaml_Password.Password)) { + m_currpassword = m_password.xaml_Password.Password; m_password.Close(); m_password = null; StartViewer(); @@ -1576,11 +1714,11 @@ namespace gsview String options = null; bool use_gs = true; String init_file = CreatePDFXA(type); - ; + switch (type) { case Save_Type_t.PDF: - /* All done. No need to use gs */ + /* All done. No need to use gs or mupdf */ System.IO.File.Copy(m_currfile, dlg.FileName, true); use_gs = false; break; @@ -1632,13 +1770,13 @@ namespace gsview bool use_mupdf = true; switch (type) { - case Save_Type_t.PCLBitmap: - break; - case Save_Type_t.PNG: - break; - case Save_Type_t.PWG: - break; - case Save_Type_t.SVG: + case Save_Type_t.LINEAR_PDF: + dlg.Filter = "PDF (*.pdf)|*.pdf"; + if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + mu_doc.PDFExtract(m_currfile, dlg.FileName, m_currpassword, + m_currpassword != null, true, -1, null); + } break; case Save_Type_t.PCLXL: use_mupdf = false; @@ -1672,31 +1810,11 @@ namespace gsview } } - private void SavePNG(object sender, RoutedEventArgs e) - { - SaveFile(Save_Type_t.PNG); - } - - private void SavePWG(object sender, RoutedEventArgs e) - { - SaveFile(Save_Type_t.PWG); - } - - private void SavePNM(object sender, RoutedEventArgs e) - { - SaveFile(Save_Type_t.PNM); - } - private void SaveSVG(object sender, RoutedEventArgs e) { SaveFile(Save_Type_t.SVG); } - private void SavePCL(object sender, RoutedEventArgs e) - { - SaveFile(Save_Type_t.PCLBitmap); - } - private void SavePDF(object sender, RoutedEventArgs e) { SaveFile(Save_Type_t.PDF); @@ -1709,7 +1827,12 @@ namespace gsview private void SaveHTML(object sender, RoutedEventArgs e) { + SaveFile(Save_Type_t.HTML); + } + private void Linearize(object sender, RoutedEventArgs e) + { + SaveFile(Save_Type_t.LINEAR_PDF); } private void SavePDF13(object sender, RoutedEventArgs e) @@ -3022,9 +3145,9 @@ namespace gsview { var relPoint = e.GetPosition(xaml_PageList); var absPoint = this.PointToScreen(relPoint); - Console.Write("abs Y position = " + absPoint.Y + "\n"); + /* Console.Write("abs Y position = " + absPoint.Y + "\n"); Console.Write("rel Y position = " + relPoint.Y + "\n"); - Console.Write("Height is = " + (this.Top + this.Height) + "\n"); + Console.Write("Height is = " + (this.Top + this.Height) + "\n"); */ if (xaml_PageList.IsMouseCaptured == true) { @@ -3086,22 +3209,21 @@ namespace gsview private void dispatcherTimerTick(object sender, EventArgs e) { var position = this.PointToScreen(Mouse.GetPosition(xaml_PageList)); - Console.Write("Y position = " + position.Y + "\n"); + /* Console.Write("Y position = " + position.Y + "\n"); Console.Write("Top position = " + this.Top + "\n"); - Console.Write("Bottom position = " + (this.Top + this.Height) + "\n"); - + Console.Write("Bottom position = " + (this.Top + this.Height) + "\n"); */ DocPage page; int page_num; if (!xaml_PageList.IsMouseCaptured) { - Console.Write("Lost capture\n"); + //Console.Write("Lost capture\n"); return; } - else + /*else { Console.Write("Have capture\n"); - } + } */ /* Get our most recent page */ var pageinfo = m_textSelect[m_textSelect.Count - 1]; page_num = pageinfo.pagenum; @@ -3423,7 +3545,7 @@ namespace gsview } - private void ExtractPages(object sender, RoutedEventArgs e) + private void SaveXML(object sender, RoutedEventArgs e) { } diff --git a/platform/winrt/gsview/PageExtractSave.xaml b/platform/winrt/gsview/PageExtractSave.xaml new file mode 100644 index 00000000..cbc57522 --- /dev/null +++ b/platform/winrt/gsview/PageExtractSave.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + Pages: + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use drag/drop to rearrange. Right click to delete from list. + Only selected pages extracted. + + + diff --git a/platform/winrt/gsview/PageExtractSave.xaml.cs b/platform/winrt/gsview/PageExtractSave.xaml.cs new file mode 100644 index 00000000..445141f7 --- /dev/null +++ b/platform/winrt/gsview/PageExtractSave.xaml.cs @@ -0,0 +1,214 @@ +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.ComponentModel; +using System.Collections.ObjectModel; + +namespace gsview +{ + public partial class PageExtractSave : Window + { + public List Pages; + SelectPage selectedpage = null; + int dropafterposition; + bool putattop = false; + + /* Callback to Main */ + internal delegate void ExtractCallBackMain(object gsObject); + internal event ExtractCallBackMain ExtractMain; + + public PageExtractSave(int num_pages) + { + InitializeComponent(); + Pages = new List(); + SetPageList(num_pages); + xaml_PageList.ItemsSource = Pages; + } + + private void AllPages(object sender, RoutedEventArgs e) + { + xaml_PageList.SelectAll(); + } + + public void SetPageList(int num_pages) + { + for (int k = 1; k < num_pages + 1; k++) + { + SelectPage Spage = new SelectPage(); + Spage.Page = k; + Spage.PageString = k; + Pages.Add(Spage); + } + } + + private void EvenPages(object sender, RoutedEventArgs e) + { + /* First check if any are selected */ + var item = xaml_PageList.SelectedItem; + + /* If none are selected then get all the evens. otherwise just get + * all the evens of the pages that have been selected */ + if (item == null) + { + /* Turn on the evens */ + for (int kk = 1; kk < Pages.Count; kk = kk + 2) + (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = true; + } + else + { + /* Turn off any odds */ + for (int kk = 0; kk < Pages.Count; kk = kk + 2) + (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = false; + } + } + + private void OddPages(object sender, RoutedEventArgs e) + { + /* First check if any are selected */ + var item = xaml_PageList.SelectedItem; + + /* If none are selected then get all the odds. otherwise just get + all the odds of the pages that have been selected */ + if (item == null) + { + /* Turn on the odds */ + for (int kk = 0; kk < Pages.Count; kk = kk + 2) + (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = true; + } + else + { + /* Turn off any evens */ + for (int kk = 1; kk < Pages.Count; kk = kk + 2) + (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = false; + } + } + + private void ExtractPages(object sender, RoutedEventArgs e) + { + ExtractMain(this); + } + + private void ExtractLeftButtonDown(object sender, MouseButtonEventArgs e) + { + int index = GetCurrentIndex(); + if (index > -1 && index < Pages.Count) + selectedpage = Pages[index]; + } + + private void ExtractLeftButtonUp(object sender, MouseButtonEventArgs e) + { + /* Check if we have something selected */ + if (selectedpage == null) + { + Cursor = Cursors.Arrow; + return; + } + + Point posit = e.GetPosition(xaml_PageList); + dropafterposition = GetCurrentIndex(); + putattop = false; + + if (dropafterposition < 0) + { + /* Check if we are above or below */ + if (posit.Y < 0) + putattop = true; + else + dropafterposition = xaml_PageList.Items.Count - 1; + } + Cursor = Cursors.Arrow; + MoveItem(); + selectedpage = null; + } + + private void MoveItem() + { + if (putattop) + { + Pages.Remove(selectedpage); + Pages.Insert(0, selectedpage); + } + else + { + Pages.Remove(selectedpage); + Pages.Insert(dropafterposition, selectedpage); + } + xaml_PageList.Items.Refresh(); + } + + private void ExtractMouseMove(object sender, MouseEventArgs e) + { + if (Mouse.LeftButton == MouseButtonState.Pressed) + Cursor = Cursors.Hand; + } + + private void ExtractMouseLeave(object sender, MouseEventArgs e) + { + Cursor = Cursors.Arrow; + } + + private void RightButtonDown(object sender, MouseButtonEventArgs e) + { + var contextmenu = new System.Windows.Controls.ContextMenu(); + this.ContextMenu = contextmenu; + + var m1 = new System.Windows.Controls.MenuItem(); + m1.Header = "Delete"; + m1.Click += cntxDeleteItem; + contextmenu.Items.Add(m1); + } + + /* Delete all selected items */ + private void cntxDeleteItem(object sender, RoutedEventArgs e) + { + /* Go backwards */ + var temp = xaml_PageList.SelectedItems; + int max = temp.Count; ; + for (int i = 0; i < max; i++) + { + var item = temp[i]; + Pages.Remove((SelectPage)item); + } + xaml_PageList.Items.Refresh(); + } + + int GetCurrentIndex() + { + int index = -1; + for (int i = 0; i < this.xaml_PageList.Items.Count; ++i) + { + ListViewItem item = GetListViewItem(i); + if (item.IsMouseOver) + { + index = i; + break; + } + } + return index; + } + + ListViewItem GetListViewItem(int index) + { + if (this.xaml_PageList.ItemContainerGenerator.Status != + System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated) + return null; + return this.xaml_PageList.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem; + } + + private void Reverse(object sender, RoutedEventArgs e) + { + Pages.Reverse(); + xaml_PageList.Items.Refresh(); + } + } +} diff --git a/platform/winrt/gsview/ghostsharp.cs b/platform/winrt/gsview/ghostsharp.cs index 5922ee00..0d52dca8 100644 --- a/platform/winrt/gsview/ghostsharp.cs +++ b/platform/winrt/gsview/ghostsharp.cs @@ -12,11 +12,16 @@ namespace gsview { /* Warning. This list is in a particular order. The devices before * psdrgb do not support multiple pages. Those including psdrgb do - * support multiple pages. This is used in the conversion process */ + * support multiple pages. This is used in the conversion process. + * Also note that mupdf devices go at the beginning of the list */ public enum gsDevice_t { - bmp16, + svg, + pnm, + pclbitmap, + pwg, + bmp16, /* Add mupdf devices before this one */ bmp16m, bmp256, bmp32b, @@ -37,7 +42,7 @@ namespace gsview pnggray, pngmono, psdcmyk, - psdrgb, /* Add single page devices before this device */ + psdrgb, /* Add single page gs devices before this device */ pdfwrite, ps2write, pxlcolor, diff --git a/platform/winrt/gsview/gsview.csproj b/platform/winrt/gsview/gsview.csproj index 707fdc05..fc9f6ddd 100644 --- a/platform/winrt/gsview/gsview.csproj +++ b/platform/winrt/gsview/gsview.csproj @@ -98,6 +98,9 @@ OutputIntent.xaml + + PageExtractSave.xaml + Password.xaml @@ -141,6 +144,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/platform/winrt/gsview/mudocument.cs b/platform/winrt/gsview/mudocument.cs index be8e4b50..404a0777 100644 --- a/platform/winrt/gsview/mudocument.cs +++ b/platform/winrt/gsview/mudocument.cs @@ -7,12 +7,62 @@ using System.Threading; using System.Runtime.InteropServices; using System.Security; using System.Windows; +using System.ComponentModel; /* This file contains the interface between the muctx cpp class, which implements the mupdf calls and the .net managed code */ namespace gsview { + /* Parameters for conversion */ + public struct ConvertParams_t + { + public int resolution; + public gsDevice_t device; + public String outputfile; + public int num_pages; + public System.Collections.IList pages; + public int currpage; + public GS_Result_t result; + }; + + /* Must match enum in muctx.h */ + enum mudevice_t + { + SVG_OUT, + PNM_OUT, + PCL_OUT, + PWG_OUT, + }; + + public class muPDFEventArgs : EventArgs + { + private bool m_completed; + private int m_progress; + private ConvertParams_t m_param; + + public bool Completed + { + get { return m_completed; } + } + + public ConvertParams_t Params + { + get { return m_param; } + } + + public int Progress + { + get { return m_progress; } + } + + public muPDFEventArgs(bool completed, int progress, ConvertParams_t param) + { + m_completed = completed; + m_progress = progress; + m_param = param; + } + } public struct content_s { @@ -24,6 +74,12 @@ namespace gsview class mudocument { IntPtr mu_object; + BackgroundWorker m_worker; + ConvertParams_t m_params; + /* Callbacks to Main */ + internal delegate void mupdfCallBackMain(object gsObject, muPDFEventArgs info); + internal event mupdfCallBackMain mupdfUpdateMain; + private System.Object m_lock = new System.Object(); public List contents; @@ -147,6 +203,17 @@ namespace gsview int line_num, int item_num, ref double top_x, ref double top_y, ref double height, ref double width); + [DllImport("mupdfnet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mExtractPages(String infile, String outfile, + String password, bool has_password, bool linearize, int num_pages, + IntPtr pages); + + [DllImport("mupdfnet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mSavePage(IntPtr ctx, String outfile, + int page_num, int res, int type, bool append); + public status_t Initialize() { mu_object = mInitialize(); @@ -423,5 +490,178 @@ namespace gsview { mReleaseText(mu_object, textpage); } + + public void PDFExtract(String infile, String outfile, String password, + bool has_password, bool linearize, int num_pages, System.Collections.IList pages) + { + if (num_pages > 0) + { + /* We need to do an allocation for our array of page numbers and + * perform pinning to avoid GC while in the c++ code */ + GCHandle pagesPtrStable; + int[] page_list; + page_list = new int[pages.Count]; + + for (int kk = 0; kk < pages.Count; kk++) + { + SelectPage currpage = (SelectPage)pages[kk]; + page_list[kk] = currpage.Page; + } + pagesPtrStable = GCHandle.Alloc(page_list, GCHandleType.Pinned); + mExtractPages(infile, outfile, password, has_password, linearize, + num_pages, pagesPtrStable.AddrOfPinnedObject()); + pagesPtrStable.Free(); + } + else + { + mExtractPages(infile, outfile, password, has_password, linearize, + num_pages, IntPtr.Zero); + } + } + + public gsStatus ConvertSave(gsDevice_t device, String outputFile, int num_pages, + System.Collections.IList pages, int resolution) + { + ConvertParams_t convertparams = new ConvertParams_t(); + + convertparams.device = device; + convertparams.outputfile = outputFile; + convertparams.num_pages = num_pages; + convertparams.resolution = resolution; + convertparams.pages = pages; + convertparams.currpage = 1; + return ConvertMuPDF(convertparams); + } + + /* Render page by page in background with progress call back */ + private gsStatus ConvertMuPDF(ConvertParams_t Params) + { + try + { + if (m_worker != null && m_worker.IsBusy) + { + m_worker.CancelAsync(); + return gsStatus.GS_BUSY; + } + if (m_worker == null) + { + m_worker = new BackgroundWorker(); + m_worker.WorkerReportsProgress = true; + m_worker.WorkerSupportsCancellation = true; + m_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(MuPDFCompleted); + m_worker.ProgressChanged += new ProgressChangedEventHandler(MuPDFProgressChanged); + m_worker.DoWork += new DoWorkEventHandler(MuPDFWork); + } + + m_params = Params; + m_worker.RunWorkerAsync(Params); + return gsStatus.GS_READY; + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during mupdf rendering\n"); + return gsStatus.GS_ERROR; + } + } + + private void MuPDFCompleted(object sender, RunWorkerCompletedEventArgs e) + { + ConvertParams_t Value; + muPDFEventArgs info; + + if (e.Cancelled) + { + Value = new ConvertParams_t(); + Value.result = GS_Result_t.gsCANCELLED; + info = new muPDFEventArgs(true, 100, Value); + } + else + { + Value = (ConvertParams_t)e.Result; + info = new muPDFEventArgs(true, 100, Value); + } + mupdfUpdateMain(this, info); + } + + private void MuPDFProgressChanged(object sender, ProgressChangedEventArgs e) + { + /* Callback with progress */ + ConvertParams_t Value = new ConvertParams_t(); + muPDFEventArgs info = new muPDFEventArgs(false, e.ProgressPercentage, Value); + mupdfUpdateMain(this, info); + } + + public void Cancel() + { + m_worker.CancelAsync(); + } + + /* ToDo: do we report pages that failed? or just push on */ + private void MuPDFWork(object sender, DoWorkEventArgs e) + { + ConvertParams_t muparams = (ConvertParams_t)e.Argument; + String out_file = muparams.outputfile; + int num_pages = muparams.num_pages; + int resolution = muparams.resolution; + var pages = muparams.pages; + BackgroundWorker worker = sender as BackgroundWorker; + + muparams.result = GS_Result_t.gsOK; + + int result; + + for (int kk = 0; kk < num_pages; kk++) + { + SelectPage curr_page = (SelectPage)pages[kk]; + int page_num = curr_page.Page; + bool append = (kk != 0); + + /* Look for file extension. */ + string extension = System.IO.Path.GetExtension(out_file); + int len = extension.Length; + String new_out_file = out_file.Substring(0, out_file.Length - len); + String out_file_name = new_out_file + "_" + page_num + extension; + + /* Question: is lock valid when done from this worker thread? */ + switch (muparams.device) + { + case gsDevice_t.svg: + lock (this.m_lock) /* Single-page format */ + result = mSavePage(mu_object, out_file_name, + page_num - 1, resolution, (int) mudevice_t.SVG_OUT, + false); + break; + case gsDevice_t.pnm: + lock (this.m_lock) /* Single-page format */ + result = mSavePage(mu_object, out_file_name, + page_num - 1, resolution, (int)mudevice_t.PNM_OUT, + false); + break; + case gsDevice_t.pclbitmap: /* Multi-page format */ + lock (this.m_lock) + result = mSavePage(mu_object, out_file, + page_num - 1, resolution, (int)mudevice_t.PCL_OUT, + append); + break; + case gsDevice_t.pwg: /* Multi-page format */ + lock (this.m_lock) + result = mSavePage(mu_object, out_file, + page_num - 1, resolution, (int)mudevice_t.PWG_OUT, + append); + break; + } + double prog = (double) (kk+1.0)/((double) num_pages) * 100.0; + worker.ReportProgress((int)prog); + + if (worker.CancellationPending == true) + { + e.Cancel = true; + muparams.result = GS_Result_t.gsCANCELLED; + break; + } + } + e.Result = muparams; + return; + } } } diff --git a/platform/winrt/libmupdf_winRT.vcxproj b/platform/winrt/libmupdf_winRT.vcxproj index c8adbcd5..1cee1c4d 100644 --- a/platform/winrt/libmupdf_winRT.vcxproj +++ b/platform/winrt/libmupdf_winRT.vcxproj @@ -158,7 +158,6 @@ - @@ -215,6 +214,7 @@ + diff --git a/platform/winrt/libmupdf_winRT.vcxproj.filters b/platform/winrt/libmupdf_winRT.vcxproj.filters index a5e907aa..f1d09539 100644 --- a/platform/winrt/libmupdf_winRT.vcxproj.filters +++ b/platform/winrt/libmupdf_winRT.vcxproj.filters @@ -426,9 +426,6 @@ tools - - tools - @@ -632,5 +629,8 @@ pdf + + !include + \ No newline at end of file diff --git a/platform/winrt/mupdfnet/mupdfnet.cpp b/platform/winrt/mupdfnet/mupdfnet.cpp index d1a53454..0a582c7b 100644 --- a/platform/winrt/mupdfnet/mupdfnet.cpp +++ b/platform/winrt/mupdfnet/mupdfnet.cpp @@ -333,3 +333,95 @@ SYMBOL_DECLSPEC int __stdcall mGetTextCharacter(void *page, int block_num, int l return cab.c; } + +/* pdf clean methods */ +SYMBOL_DECLSPEC int __stdcall mExtractPages(PCWSTR infile, PCWSTR outfile, + PCWSTR password, bool has_password, bool linearize, int num_pages, void *pages) +{ + int argc = 3 + ((has_password) ? (2) : (0)) + ((linearize) ? (1) : (0)) + ((num_pages > 0) ? (1) : (0)); + char **argv; + int size_pages; + char *infilechar = String_to_char(infile); + char *outfilechar = String_to_char(outfile); + char *passchar; + int *pagenum = (int*) pages; + char *pagenums; + char* num; + int num_size; + int result; + int pos = 1; + + argv = new char*[argc]; + + if (has_password) + { + passchar = String_to_char(password); + argv[pos++] = "-p"; + argv[pos++] = passchar; + } + if (linearize) + { + argv[pos++] = "-l"; + } + + argv[pos++] = infilechar; + argv[pos++] = outfilechar; + + if (num_pages > 0) + { + /* Get last page, for number length and number of pages */ + int last = pagenum[num_pages - 1]; + if (last == 0) + { + num_size = 1; + size_pages = num_size; + } + else + { + num_size = floor(log10(last)) + 1; + size_pages = (num_size + 1) * num_pages; + } + + /* Create the list of page numbers */ + pagenums = new char[size_pages + 1]; + pagenums[0] = '\0'; + num = new char[num_size + 2]; + for (int kk = 0; kk < num_pages; kk++) + { + if (kk < num_pages - 1) + sprintf(num, "%d,", pagenum[kk]); + else + sprintf(num, "%d", pagenum[kk]); + strcat(pagenums, num); + } + argv[pos++] = pagenums; + } + + + result = pdfclean_main(argc, argv); + + delete(num); + delete(infilechar); + delete(outfilechar); + if (has_password) + delete(passchar); + if (num_pages > 0) + delete(pagenums); + delete(argv); + return result; +} + +/* output methods */ +SYMBOL_DECLSPEC int __stdcall mSavePage(void *ctx, PCWSTR outfile, int page_num, + int resolution, int type, bool append) +{ + muctx *mu_ctx = static_cast(ctx); + char *outfilechar = String_to_char(outfile); + status_t result = mu_ctx->SavePage(outfilechar, page_num, resolution, type, + append); + delete(outfilechar); + if (result == S_ISOK) + return 0; + else + return -1; +} diff --git a/platform/winrt/mupdfnet/mupdfnet.h b/platform/winrt/mupdfnet/mupdfnet.h index 34d4a034..0d873a77 100644 --- a/platform/winrt/mupdfnet/mupdfnet.h +++ b/platform/winrt/mupdfnet/mupdfnet.h @@ -61,4 +61,11 @@ EXTERN_C SYMBOL_DECLSPEC int __stdcall mGetTextCharacter(void *text, int block_n int line_num, int item_num, double *top_x, double *top_y, double *height, double *width); -EXTERN_C SYMBOL_DECLSPEC void __stdcall mReleaseText(void *ctx, void *page); \ No newline at end of file +EXTERN_C SYMBOL_DECLSPEC void __stdcall mReleaseText(void *ctx, void *page); + +/* pdfclean methods */ +EXTERN_C SYMBOL_DECLSPEC int __stdcall mExtractPages(PCWSTR infile, PCWSTR outfile, + PCWSTR password, bool has_password, int num_pages, void *pages); +/* output */ +EXTERN_C SYMBOL_DECLSPEC int __stdcall mSavePage(void *ctx, PCWSTR outfile, int page_num, + int resolution, int type, bool append); diff --git a/platform/winrt/mupdfwinrt/muctx.cpp b/platform/winrt/mupdfwinrt/muctx.cpp index 4dcb9423..f7dfd20b 100644 --- a/platform/winrt/mupdfwinrt/muctx.cpp +++ b/platform/winrt/mupdfwinrt/muctx.cpp @@ -220,7 +220,7 @@ int muctx::GetPageCount() int muctx::MeasurePage(int page_num, point_t *size) { fz_rect rect; - fz_page *page; + fz_page *page = NULL; fz_rect *bounds; fz_try(mu_ctx) @@ -230,6 +230,10 @@ int muctx::MeasurePage(int page_num, point_t *size) size->X = bounds->x1 - bounds->x0; size->Y = bounds->y1 - bounds->y0; } + fz_always(mu_ctx) + { + fz_free_page(mu_doc, page); + } fz_catch(mu_ctx) { return E_FAIL; @@ -697,3 +701,98 @@ void muctx::ReleaseText(void *text) fz_text_page *text_page = (fz_text_page*) text; fz_free_text_page(mu_ctx, text_page); } + +/* To do: banding */ +status_t muctx::SavePage(char *filename, int page_num, int resolution, int type, + bool append) +{ + float zoom; + fz_matrix ctm; + fz_rect bounds, tbounds; + FILE *file = NULL; + fz_output *out = NULL; + fz_device *dev = NULL; + int width, height; + fz_display_list *dlist = NULL; + fz_page *page = NULL; + bool valid = true; + fz_pixmap *pix = NULL; + fz_irect ibounds; + + fz_var(dev); + fz_var(page); + fz_var(dlist); + fz_var(pix); + + fz_try(mu_ctx) + { + page = fz_load_page(mu_doc, page_num); + fz_bound_page(mu_doc, page, &bounds); + zoom = resolution / 72; + fz_scale(&ctm, zoom, zoom); + tbounds = bounds; + fz_transform_rect(&tbounds, &ctm); + fz_round_rect(&ibounds, &tbounds); + + /* First see if we have this one in the cache */ + dlist = page_cache->Use(page_num, &width, &height, mu_ctx); + + if (type == SVG_OUT) + { + file = fopen(filename, "wb"); + if (file == NULL) + fz_throw(mu_ctx, FZ_ERROR_GENERIC, "cannot open file '%s'", filename); + out = fz_new_output_with_file(mu_ctx, file); + + dev = fz_new_svg_device(mu_ctx, out, tbounds.x1 - tbounds.x0, tbounds.y1 - tbounds.y0); + if (dlist != NULL) + fz_run_display_list(dlist, dev, &ctm, &tbounds, NULL); + else + fz_run_page(mu_doc, page, dev, &ctm, NULL); + } + else + { + pix = fz_new_pixmap_with_bbox(mu_ctx, fz_device_rgb(mu_ctx), &ibounds); + fz_pixmap_set_resolution(pix, resolution); + fz_clear_pixmap_with_value(mu_ctx, pix, 255); + dev = fz_new_draw_device(mu_ctx, pix); + if (dlist != NULL) + fz_run_display_list(dlist, dev, &ctm, &tbounds, NULL); + else + fz_run_page(mu_doc, page, dev, &ctm, NULL); + switch (type) + { + case PNM_OUT: + fz_write_pnm(mu_ctx, pix, filename); + break; + case PCL_OUT: /* This can do multi-page */ + fz_pcl_options options; + fz_pcl_preset(mu_ctx, &options, "ljet4"); + fz_write_pcl(mu_ctx, pix, filename, append, &options); + break; + case PWG_OUT: /* This can do multi-page */ + fz_write_pwg(mu_ctx, pix, filename, append, NULL); + break; + } + } + } + fz_always(mu_ctx) + { + if (pix != NULL) + fz_drop_pixmap(mu_ctx, pix); + fz_free_device(dev); + fz_free_page(mu_doc, page); + if (dlist != NULL) + fz_drop_display_list(mu_ctx, dlist); + if (out != NULL) + { + fz_close_output(out); + fclose(file); + } + } + fz_catch(mu_ctx) + { + return E_FAILURE; + } + return S_ISOK; +} \ No newline at end of file diff --git a/platform/winrt/mupdfwinrt/muctx.h b/platform/winrt/mupdfwinrt/muctx.h index 79607987..8db81f1d 100644 --- a/platform/winrt/mupdfwinrt/muctx.h +++ b/platform/winrt/mupdfwinrt/muctx.h @@ -8,11 +8,14 @@ #include "Cache.h" extern "C" { #include "mupdf/fitz.h" +#include "mupdf/pdf-tools.h" } #define MAX_SEARCH 500 +enum { SVG_OUT, PNM_OUT, PCL_OUT, PWG_OUT }; + typedef struct point_s { double X; @@ -104,6 +107,9 @@ public: void ReleaseText(void *text); bool RequiresPassword(void); bool ApplyPassword(char* password); + status_t SavePage(char *filename, int pagenum, int resolution, int type, + bool append); + #ifdef _WINRT_DLL status_t InitializeStream(IRandomAccessStream^ readStream, char *ext); #else -- cgit v1.2.3