using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
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.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.ComponentModel;
using System.IO;
using System.Windows.Xps.Packaging;
using System.Printing;
using System.Windows.Markup;
using System.Runtime.InteropServices;
using Microsoft.Win32; /* For registry */
using System.Reflection;
using System.Diagnostics;
public enum AA_t
{
HIGH = 8,
MEDHIGH = 6,
MED = 4,
LOW = 2,
NONE = 0
}
enum PDFType_t
{
PDFX,
PDFA
}
enum AppBar_t
{
TEXT_SEARCH,
STANDARD
}
enum NotifyType_t
{
MESS_STATUS,
MESS_ERROR
};
enum RenderingStatus_t
{
REN_AVAILABLE,
REN_THUMBS,
REN_UPDATE_THUMB_CANVAS,
REN_PAGE /* Used to ignore value when source based setting */
};
public enum status_t
{
S_ISOK,
E_FAILURE,
E_OUTOFMEM,
E_NEEDPASSWORD
};
public enum textout_t
{
HTML = 0,
XML,
TEXT
}
enum zoom_t
{
NO_ZOOM,
ZOOM_IN,
ZOOM_OUT
}
enum view_t
{
VIEW_WEB,
VIEW_CONTENT,
VIEW_PAGE,
VIEW_PASSWORD,
VIEW_TEXTSEARCH
};
public enum Page_Content_t
{
FULL_RESOLUTION = 0,
THUMBNAIL,
OLD_RESOLUTION,
NOTSET
};
/* Put all the PDF types first to make the switch statment shorter
Save_Type_t.PDF is the test */
public enum Save_Type_t
{
PDF13,
LINEAR_PDF,
PDFA1_RGB,
PDFA1_CMYK,
PDFA2_RGB,
PDFA2_CMYK,
PDFX3_GRAY,
PDFX3_CMYK,
PDF,
PCLXL,
XPS,
SVG,
TEXT,
HTML,
XML
}
public enum Extract_Type_t
{
PDF,
EPS,
PS,
SVG
}
/* C# has no defines.... */
static class Constants
{
public const int SCROLL_STEPSIZE = 48;
public const int INIT_LOOK_AHEAD = 2; /* A + count on the pages to pre-render */
public const int THUMB_PREADD = 10;
public const double MIN_SCALE = 0.5;
public const double SCALE_THUMB = 0.05;
public const int BLANK_WIDTH = 17;
public const int BLANK_HEIGHT = 22;
public const double ZOOM_STEP = 0.25;
public const int ZOOM_MAX = 4;
public const double ZOOM_MIN = 0.25;
public const int KEY_PLUS = 0xbb;
public const int KEY_MINUS = 0xbd;
public const int ZOOM_IN = 0;
public const int ZOOM_OUT = 1;
public const double SCREEN_SCALE = 1;
public const int HEADER_SIZE = 54;
public const int SEARCH_FORWARD = 1;
public const int SEARCH_BACKWARD = -1;
public const int TEXT_NOT_FOUND = -1;
public const int DEFAULT_GS_RES = 300;
public const int DISPATCH_TIME = 50;
public const int SCROLL_STEP = 10;
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
{
public const string PDF = "Portable Document Format";
public const string PS = "PostScript";
public const string XPS = "XPS";
public const string EPS = "Encapsulated PostScript";
public const string CBZ = "Comic Book Archive";
public const string PNG = "Portable Network Graphics Image";
public const string JPG = "Joint Photographic Experts Group Image";
public const string UNKNOWN = "Unknown";
}
namespace gsview
{
///
/// Interaction logic for MainWindow.xaml
///
///
public struct pageprogress_t
{
public Byte[] bitmap;
public BlocksText charlist;
public int pagenum;
public Point size;
public Annotate_t annot;
}
public struct ContextMenu_t
{
public int page_num;
public Point mouse_position;
}
public struct thumb_t
{
public int page_num;
public Byte[] bitmap;
public Point size;
}
public struct searchResults_t
{
public String needle;
public bool done;
public int page_found;
public List rectangles;
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;
public bool first_line_full;
public bool last_line_full;
}
public static class ScrollBarExtensions
{
public static double GetThumbCenter(this System.Windows.Controls.Primitives.ScrollBar s)
{
double thumbLength = GetThumbLength(s);
double trackLength = s.Maximum - s.Minimum;
return thumbLength / 2 + s.Minimum + (s.Value - s.Minimum) *
(trackLength - thumbLength) / trackLength;
}
public static void SetThumbCenter(this System.Windows.Controls.Primitives.ScrollBar s, double thumbCenter)
{
double thumbLength = GetThumbLength(s);
double trackLength = s.Maximum - s.Minimum;
if (thumbCenter >= s.Maximum - thumbLength / 2)
{
s.Value = s.Maximum;
}
else if (thumbCenter <= s.Minimum + thumbLength / 2)
{
s.Value = s.Minimum;
}
else if (thumbLength >= trackLength)
{
s.Value = s.Minimum;
}
else
{
s.Value = (int)(s.Minimum + trackLength *
((thumbCenter - s.Minimum - thumbLength / 2)
/ (trackLength - thumbLength)));
}
}
public static double GetThumbLength(this System.Windows.Controls.Primitives.ScrollBar s)
{
double trackLength = s.Maximum - s.Minimum;
return trackLength * s.ViewportSize /
(trackLength + s.ViewportSize);
}
public static void SetThumbLength(this System.Windows.Controls.Primitives.ScrollBar s, double thumbLength)
{
double trackLength = s.Maximum - s.Minimum;
if (thumbLength < 0)
{
s.ViewportSize = 0;
}
else if (thumbLength < trackLength)
{
s.ViewportSize = trackLength * thumbLength / (trackLength - thumbLength);
}
else
{
s.ViewportSize = double.MaxValue;
}
}
}
public partial class MainWindow : Window
{
mudocument mu_doc = null;
public Pages m_docPages;
List m_textSelect;
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;
private bool m_file_open;
private int m_currpage;
private int m_searchpage;
private int m_num_pages;
private bool m_init_done;
private bool m_links_on;
String m_textsearchcolor = "#4072AC25";
String m_textselectcolor = "#402572AC";
String m_regionselect = "#00FFFFFF";
String m_blockcolor = "#00FFFFFF";
//String m_regionselect = "#FFFF0000"; /* Debug */
String m_linkcolor = "#40AC7225";
private bool m_have_thumbs;
double m_doczoom;
ghostsharp m_ghostscript;
String m_currfile;
String m_origfile;
private gsprint m_ghostprint = null;
bool m_isXPS;
bool m_isImage;
gsOutput m_gsoutput;
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;
OutputIntent m_outputintents;
Selection m_selection;
String m_prevsearch = null;
bool m_clipboardset;
bool m_doscroll;
bool m_intxtselect;
bool m_textselected;
System.Windows.Threading.DispatcherTimer m_dispatcherTimer = null;
double m_lastY;
double m_maxY;
bool m_ignorescrollchange;
double m_totalpageheight;
AA_t m_AA;
bool m_regstartup;
int m_initpage;
bool m_selectall;
bool m_showannot;
bool m_ScrolledChanged;
public MainWindow()
{
InitializeComponent();
this.Closing += new System.ComponentModel.CancelEventHandler(Window_Closing);
m_file_open = false;
m_regstartup = true;
m_showannot = true;
/* Allocations and set up */
try
{
m_docPages = new Pages();
m_thumbnails = new List();
m_PrintPreviewPage = new DocPage();
m_lineptrs = new List();
m_textptrs = new List();
m_textset = new List();
m_ghostscript = new ghostsharp();
m_ghostscript.gsUpdateMain += new ghostsharp.gsCallBackMain(gsProgress);
m_gsoutput = new gsOutput();
m_gsoutput.Activate();
m_outputintents = new OutputIntent();
m_outputintents.Activate();
m_ghostscript.gsIOUpdateMain += new ghostsharp.gsIOCallBackMain(gsIO);
m_ghostscript.gsDLLProblemMain += new ghostsharp.gsDLLProblem(gsDLL);
m_convertwin = null;
m_extractwin = null;
m_selection = null;
xaml_ZoomSlider.AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(ZoomReleased), true);
xaml_PageList.AddHandler(Grid.DragOverEvent, new System.Windows.DragEventHandler(Grid_DragOver), true);
xaml_PageList.AddHandler(Grid.DropEvent, new System.Windows.DragEventHandler(Grid_Drop), true);
DimSelections();
status_t result = CleanUp();
string[] arguments = Environment.GetCommandLineArgs();
if (arguments.Length > 1)
{
string filePath = arguments[1];
ProcessFile(filePath);
}
else
{
if (m_regstartup)
InitFromRegistry();
}
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Memory allocation failed at initialization\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
private void Grid_DragOver(object sender, System.Windows.DragEventArgs e)
{
if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))
{
e.Effects = System.Windows.DragDropEffects.All;
}
else
{
e.Effects = System.Windows.DragDropEffects.None;
}
e.Handled = false;
}
private void Grid_Drop(object sender, System.Windows.DragEventArgs e)
{
if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))
{
string[] docPath = (string[]) e.Data.GetData(System.Windows.DataFormats.FileDrop);
ProcessFile(String.Join("",docPath));
}
}
void CloseExtraWindows(bool shutdown)
{
if (m_selection != null)
m_selection.Close();
if (m_convertwin != null)
m_convertwin.Close();
if (m_extractwin != null)
m_extractwin.Close();
if (m_infowindow != null)
m_infowindow.Close();
if (shutdown)
{
if (m_gsoutput != null)
m_gsoutput.RealWindowClosing();
if (m_outputintents != null)
m_outputintents.RealWindowClosing();
if (m_printcontrol != null)
m_printcontrol.RealWindowClosing();
}
else
{
if (m_gsoutput != null)
m_gsoutput.Hide();
if (m_outputintents != null)
m_outputintents.Hide();
if (m_printcontrol != null)
m_printcontrol.Hide();
}
}
void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
CloseExtraWindows(true);
}
/* Stuff not enabled when source is XPS */
void EnabletoPDF()
{
xaml_savepdf.IsEnabled = true;
xaml_linearize_pdf.IsEnabled = true;
xaml_saveas.IsEnabled = true;
xaml_Extract.IsEnabled = true;
xaml_conversions.IsEnabled = true;
xaml_extractselection.IsEnabled = true;
}
void DisabletoPDF()
{
xaml_savepdf.IsEnabled = false;
xaml_linearize_pdf.IsEnabled = false;
xaml_saveas.IsEnabled = false;
xaml_Extract.IsEnabled = false;
xaml_conversions.IsEnabled = false;
xaml_extractselection.IsEnabled = false;
}
private void DimSelections()
{
xaml_currPage.Text = "";
xaml_TotalPages.Text = "/ 0";
xaml_Zoomsize.Text = "100";
xaml_BackPage.Opacity = 0.5;
xaml_Contents.Opacity = 0.5;
xaml_currPage.Opacity = 0.5;
xaml_currPage.IsEnabled = false;
xaml_ForwardPage.Opacity = 0.5;
xaml_Links.Opacity = 0.5;
xaml_Print.Opacity = 0.5;
xaml_SavePDF.Opacity = 0.5;
xaml_Search.Opacity = 0.5;
xaml_Thumbs.Opacity = 0.5;
xaml_TotalPages.Opacity = 0.5;
xaml_zoomIn.Opacity = 0.5;
xaml_zoomOut.Opacity = 0.5;
xaml_Zoomsize.Opacity = 0.5;
xaml_ExpandFill.Opacity = 0.5;
xaml_ContScrollFill.Opacity = 0.5;
xaml_ActualSize.Opacity = 0.5;
xaml_Zoomsize.IsEnabled = false;
xaml_ZoomSlider.Opacity = 0.5;
xaml_ZoomSlider.IsEnabled = false;
xaml_saveas.IsEnabled = false;
xaml_closefile.IsEnabled = false;
xaml_showinfo.IsEnabled = false;
xaml_extractselection.IsEnabled = false;
xaml_conversions.IsEnabled = false;
xaml_gsmessage.IsEnabled = false;
xaml_print_menu.IsEnabled = false;
xaml_view.IsEnabled = false;
xaml_edit.IsEnabled = false;
}
private status_t CleanUp()
{
m_init_done = false;
this.Cursor = System.Windows.Input.Cursors.Arrow;
/* Collapse this stuff since it is going to be released */
xaml_ThumbGrid.Visibility = System.Windows.Visibility.Collapsed;
xaml_ContentGrid.Visibility = System.Windows.Visibility.Collapsed;
xaml_VerticalScroll.Visibility = System.Windows.Visibility.Collapsed;
/* Clear out everything */
if (m_docPages != null && m_docPages.Count > 0)
m_docPages.Clear();
if (m_textSelect != null)
m_textSelect.Clear();
if (m_textset != null)
m_textset.Clear();
if (m_lineptrs != null && m_lineptrs.Count > 0)
m_lineptrs.Clear();
if (m_thumbnails != null && m_thumbnails.Count > 0)
m_thumbnails.Clear();
if (m_textptrs != null && m_textptrs.Count > 0)
m_textptrs.Clear();
if (m_page_link_list != null && m_page_link_list.Count > 0)
{
m_page_link_list.Clear();
m_page_link_list = null;
}
if (m_text_list != null && m_text_list.Count > 0)
{
m_text_list.Clear();
m_text_list = null;
}
if (mu_doc != null)
mu_doc.CleanUp();
try
{
mu_doc = new mudocument();
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Memory allocation failed during clean up\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
mu_doc.mupdfDLLProblemMain += new mudocument.mupdfDLLProblem(muDLL);
status_t result = mu_doc.Initialize();
mu_doc.mupdfUpdateMain += new mudocument.mupdfCallBackMain(mupdfUpdate);
if (result != status_t.S_ISOK)
{
Console.WriteLine("Library allocation failed during clean up\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Library allocation failed!");
return result;
}
m_have_thumbs = false;
m_file_open = false;
m_num_pages = -1;
m_links_on = false;
m_doczoom = 1.0;
m_isXPS = false;
m_isImage = false;
//xaml_CancelThumb.IsEnabled = true;
m_currpage = 0;
m_ignorescrollchange = false;
m_document_type = DocumentTypes.UNKNOWN;
EnabletoPDF();
m_clipboardset = false;
m_doscroll = false;
m_intxtselect = false;
m_textselected = false;
m_currpassword = null;
CloseExtraWindows(false);
ResetScroll();
m_totalpageheight = 0;
m_AA = GetAA();
m_origfile = null;
m_initpage = 0;
xaml_Zoomsize.Text = "100";
m_selectall = false;
return result;
}
private String GetVersion()
{
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
String vers = fileVersionInfo.ProductVersion;
String[] parts = vers.Split('.');
String simple_vers = parts[0] + '.' + parts[1];
return simple_vers;
}
/* Initialize from registry */
private void InitFromRegistry()
{
RegistryKey key = Registry.CurrentUser.CreateSubKey("Software");
RegistryKey keyA = key.CreateSubKey("Artifex Software");
String vers = GetVersion();
RegistryKey keygs = keyA.CreateSubKey("gsview " + vers);
String filepath = null;
Int32 page;
AA_t aa = AA_t.HIGH;
try
{
filepath = (String)keygs.GetValue("File", null);
aa = (AA_t)keygs.GetValue("AA");
page = (Int32)keygs.GetValue("Page");
}
catch
{
return;
}
keygs.Close();
keyA.Close();
key.Close();
SetAA(aa);
m_AA = aa;
if (filepath != null && File.Exists(filepath))
{
m_initpage = page;
ProcessFile(filepath);
}
else
m_initpage = 0;
}
private void SetRegistry()
{
if (m_currfile == null)
return;
RegistryKey key = Registry.CurrentUser.CreateSubKey("Software");
RegistryKey keyA = key.CreateSubKey("Artifex Software");
String vers = GetVersion();
RegistryKey keygs = keyA.CreateSubKey("gsview " + vers);
if (m_origfile != null && (m_document_type == DocumentTypes.PS ||
m_document_type == DocumentTypes.EPS))
{
keygs.SetValue("File", m_origfile, RegistryValueKind.String);
}
else
{
keygs.SetValue("File", m_currfile, RegistryValueKind.String);
}
keygs.SetValue("Page", m_currpage, RegistryValueKind.DWord);
Int32 aa_int = (Int32)m_AA;
keygs.SetValue("AA", aa_int, RegistryValueKind.DWord);
keygs.Close();
keyA.Close();
key.Close();
}
private void AppClosing(object sender, CancelEventArgs e)
{
if (m_init_done)
SetRegistry();
}
private void ShowMessage(NotifyType_t type, String Message)
{
if (type == NotifyType_t.MESS_ERROR)
{
System.Windows.Forms.MessageBox.Show(Message, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
else
{
System.Windows.Forms.MessageBox.Show(Message, "Notice",
MessageBoxButtons.OK);
}
}
private void CloseCommand(object sender, ExecutedRoutedEventArgs e)
{
if (m_init_done)
CloseDoc();
}
private void CloseDoc()
{
CleanUp();
}
/* Set the page with the new raster information */
private void UpdatePage(int page_num, Byte[] bitmap, Point ras_size,
Page_Content_t content, double zoom_in, AA_t AA)
{
DocPage doc_page = this.m_docPages[page_num];
doc_page.Width = (int)ras_size.X;
doc_page.Height = (int)ras_size.Y;
doc_page.Content = content;
doc_page.Zoom = zoom_in;
int stride = doc_page.Width * 4;
doc_page.BitMap = BitmapSource.Create(doc_page.Width, doc_page.Height,
72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride);
doc_page.PageNum = page_num;
doc_page.AA = AA;
if (content == Page_Content_t.THUMBNAIL)
{
doc_page.Width = (int)(ras_size.X / Constants.SCALE_THUMB);
doc_page.Height = (int)(ras_size.Y / Constants.SCALE_THUMB);
}
}
private void OpenFileCommand(object sender, ExecutedRoutedEventArgs e)
{
OpenFile(sender, e);
}
private void OpenFile(object sender, RoutedEventArgs e)
{
if (m_password != null && m_password.IsActive)
m_password.Close();
if (m_printcontrol != null && m_printcontrol.IsActive)
m_printcontrol.Close();
/* Release the print control regardless of it being opened.
We don't want previous documents pages in the preview */
m_printcontrol = null;
if (m_infowindow != null && m_infowindow.IsActive)
m_infowindow.Close();
/* Check if gs is currently busy. If it is then don't allow a new
* file to be opened. They can cancel gs with the cancel button if
* they want */
if (m_ghostscript.GetStatus() != gsStatus.GS_READY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "GS busy. Cancel to open new file.");
return;
}
if (m_ghostprint != null && m_ghostprint.IsBusy())
{
ShowMessage(NotifyType_t.MESS_STATUS, "Let printing complete");
return;
}
System.Windows.Forms.OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog();
dlg.Filter = "Document Files(*.ps;*.eps;*.pdf;*.xps;*.oxps;*.cbz;*.png;*.jpg;*.jpeg)|*.ps;*.eps;*.pdf;*.xps;*.oxps;*.cbz;*.png;*.jpg;*.jpeg|All files (*.*)|*.*";
dlg.FilterIndex = 1;
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
ProcessFile(dlg.FileName);
}
private void ProcessFile(String FileName)
{
if (m_file_open)
{
CloseDoc();
}
/* If we have a ps or eps file then launch the distiller first
* and then we will get a temp pdf file which will be opened by
* mupdf */
string extension = System.IO.Path.GetExtension(FileName);
/* We are doing this based on the extension but like should do
* it based upon the content */
switch (extension.ToUpper())
{
case ".PS":
m_document_type = DocumentTypes.PS;
break;
case ".EPS":
m_document_type = DocumentTypes.EPS;
break;
case ".XPS":
case ".OXPS":
m_document_type = DocumentTypes.XPS;
break;
case ".PDF":
m_document_type = DocumentTypes.PDF;
break;
case ".CBZ":
m_document_type = DocumentTypes.CBZ;
break;
case ".PNG":
m_document_type = DocumentTypes.PNG;
break;
case ".JPG":
m_document_type = DocumentTypes.JPG;
break;
case ".JPEG":
m_document_type = DocumentTypes.JPG;
break;
default:
{
ShowMessage(NotifyType_t.MESS_STATUS, "Unknown File Type");
return;
}
}
if (extension.ToUpper() == ".PS" || extension.ToUpper() == ".EPS")
{
xaml_DistillProgress.Value = 0;
if (m_ghostscript.DistillPS(FileName, Constants.DEFAULT_GS_RES) == gsStatus.GS_BUSY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "GS currently busy");
return;
}
xaml_DistillName.Text = "Distilling";
xaml_CancelDistill.Visibility = System.Windows.Visibility.Visible;
xaml_DistillName.FontWeight = FontWeights.Bold;
xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible;
return;
}
/* Set if this is already xps for printing */
if (extension.ToUpper() == ".XPS" || extension.ToUpper() == ".OXPS")
m_isXPS = true;
if (extension.ToUpper() == ".CBZ" || extension.ToUpper() == ".PNG" ||
extension.ToUpper() == ".JPG")
m_isImage = true;
OpenFile2(FileName);
}
private void OpenFile2(String File)
{
m_currfile = File;
xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Visible;
xaml_openfilestatus.Text = "Opening File";
/* The file open can take a fair amount of time. So that we can show
* an indeterminate progress bar while opening, go ahead an do this
* on a separate thread */
OpenFileBG();
}
private void OpenWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
status_t code = mu_doc.OpenFile(m_currfile);
worker.ReportProgress(100, code);
}
private void OpenProgress(object sender, ProgressChangedEventArgs e)
{
status_t result = (status_t)(e.UserState);
if (result == status_t.S_ISOK)
{
/* Check if we need a password */
if (mu_doc.RequiresPassword())
{
xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed;
GetPassword();
}
else
StartViewer();
}
else
{
m_currfile = null;
}
}
private void OpenFileBG()
{
try
{
m_openfile = new BackgroundWorker();
m_openfile.WorkerReportsProgress = true;
m_openfile.WorkerSupportsCancellation = false;
m_openfile.DoWork += new DoWorkEventHandler(OpenWork);
m_openfile.ProgressChanged += new ProgressChangedEventHandler(OpenProgress);
m_openfile.RunWorkerAsync();
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Memory allocation failed during opening\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
private void SetPageAnnot(int page_num, Annotate_t render_result)
{
if (m_docPages[page_num].Annotate == Annotate_t.UNKNOWN ||
m_docPages[page_num].Annotate == Annotate_t.COMPUTING)
{
if (render_result == Annotate_t.NO_ANNOTATE)
m_docPages[page_num].Annotate = Annotate_t.NO_ANNOTATE;
else
{
if (m_showannot)
m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_VISIBLE;
else
m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_HIDDEN;
}
}
else
{
if (m_docPages[page_num].Annotate != Annotate_t.NO_ANNOTATE)
{
if (m_showannot)
m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_VISIBLE;
else
m_docPages[page_num].Annotate = Annotate_t.ANNOTATE_HIDDEN;
}
}
}
private void InitialRenderWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int look_ahead = Math.Min(m_num_pages, Constants.INIT_LOOK_AHEAD);
/* Do the first few full res pages */
for (int k = 0; k < look_ahead; k++)
{
if (m_num_pages > k)
{
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)
{
try
{
bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
/* Synchronous call on our background thread */
code = (status_t)mu_doc.RenderPage(k, bitmap, (int)ras_size.X,
(int)ras_size.Y, scale_factor, false, true,
!(m_textset[k]), out charlist, m_showannot, out annot);
}
catch (OutOfMemoryException em)
{
Console.WriteLine("Memory allocation failed init page " + k + em.Message + "\n");
break;
}
/* create new page if we rendered ok. set ui value with
* progress call back, pass page number, charlist and bitmap */
if (code == status_t.S_ISOK)
{
pageprogress_t page_prog = new pageprogress_t();
page_prog.bitmap = bitmap;
page_prog.charlist = charlist;
page_prog.pagenum = k;
page_prog.size = ras_size;
page_prog.annot = annot;
worker.ReportProgress(100, page_prog);
}
}
}
}
}
private void InitialRenderProgressChanged(object sender, ProgressChangedEventArgs e)
{
pageprogress_t result = (pageprogress_t)(e.UserState);
int k = result.pagenum;
m_textset[k] = true;
m_textptrs[k] = result.charlist;
m_docPages[k].TextBlocks = result.charlist;
UpdatePage(k, result.bitmap, result.size, Page_Content_t.FULL_RESOLUTION, 1.0, m_AA);
m_docPages[k].NativeHeight = (int) result.size.Y;
m_docPages[k].NativeWidth = (int)result.size.X;
SetPageAnnot(k, result.annot);
}
private void InitialRenderCompleted(object sender, RunWorkerCompletedEventArgs e)
{
m_init_done = true;
m_currpage = 0;
RenderThumbs();
m_file_open = true;
xaml_BackPage.Opacity = 1;
xaml_Contents.Opacity = 1;
xaml_currPage.Opacity = 1;
xaml_ForwardPage.Opacity = 1;
xaml_Links.Opacity = 1;
xaml_Print.Opacity = 1;
xaml_SavePDF.Opacity = 1;
xaml_Search.Opacity = 1;
xaml_Thumbs.Opacity = 1;
xaml_TotalPages.Opacity = 1;
xaml_zoomIn.Opacity = 1;
xaml_zoomOut.Opacity = 1;
xaml_Zoomsize.Opacity = 1;
xaml_ExpandFill.Opacity = 1;
xaml_ContScrollFill.Opacity = 1;
xaml_ActualSize.Opacity = 1;
xaml_Zoomsize.IsEnabled = true;
xaml_currPage.IsEnabled = true;
xaml_TotalPages.Text = "/ " + m_num_pages.ToString();
xaml_currPage.Text = "1";
xaml_ZoomSlider.Opacity = 1.0;
xaml_ZoomSlider.IsEnabled = true;
xaml_closefile.IsEnabled = true;
xaml_saveas.IsEnabled = true;
xaml_showinfo.IsEnabled = true;
xaml_extractselection.IsEnabled = true;
xaml_conversions.IsEnabled = true;
xaml_gsmessage.IsEnabled = true;
xaml_print_menu.IsEnabled = true;
xaml_view.IsEnabled = true;
xaml_edit.IsEnabled = true;
if (m_isXPS || m_isImage)
DisabletoPDF();
if (m_isImage)
{
xaml_Print.IsEnabled = false;
xaml_print_menu.IsEnabled = false;
xaml_Print.Opacity = 0.5;
xaml_print_menu.Opacity = 0.5;
}
else
{
xaml_Print.IsEnabled = true;
xaml_print_menu.IsEnabled = true;
xaml_Print.Opacity = 1.0;
xaml_print_menu.Opacity = 1.0;
}
xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed;
xaml_VerticalScroll.Visibility = System.Windows.Visibility.Visible;
xaml_VerticalScroll.Value = 0;
}
private void InitialRenderBG()
{
int look_ahead = Math.Min(Constants.INIT_LOOK_AHEAD, m_num_pages);
m_currpage = 0;
m_thumbnails.Capacity = m_num_pages;
for (int k = 0; k < Constants.INIT_LOOK_AHEAD; k++)
{
m_docPages.Add(InitDocPage());
m_docPages[k].PageNum = k;
m_textptrs.Add(new BlocksText());
m_lineptrs.Add(new LinesText());
m_textset.Add(false);
}
var dummy = InitDocPage();
for (int k = Constants.INIT_LOOK_AHEAD; k < m_num_pages; k++)
{
m_docPages.Add(dummy);
m_textptrs.Add(new BlocksText());
m_lineptrs.Add(new LinesText());
m_textset.Add(false);
}
xaml_PageList.ItemsSource = m_docPages;
try
{
m_initrender = new BackgroundWorker();
m_initrender.WorkerReportsProgress = true;
m_initrender.WorkerSupportsCancellation = false;
m_initrender.DoWork += new DoWorkEventHandler(InitialRenderWork);
m_initrender.RunWorkerCompleted += new RunWorkerCompletedEventHandler(InitialRenderCompleted);
m_initrender.ProgressChanged += new ProgressChangedEventHandler(InitialRenderProgressChanged);
m_initrender.RunWorkerAsync();
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Memory allocation failed during initial render\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
private void StartViewer()
{
m_num_pages = mu_doc.GetPageCount();
if (m_num_pages == 0)
{
xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed;
CleanUp();
ShowMessage(NotifyType_t.MESS_ERROR, m_currfile + " is corrupted");
}
else
{
xaml_openfilestatus.Text = "Initial Page Rendering";
xaml_openfilestatus.UpdateLayout();
InitialRenderBG();
}
}
private status_t ComputePageSize(int page_num, double scale_factor,
out Point render_size)
{
Point renpageSize = new Point();
status_t code = (status_t)mu_doc.GetPageSize(page_num, out render_size);
if (code != status_t.S_ISOK)
return code;
renpageSize.X = (render_size.X * scale_factor);
renpageSize.Y = (render_size.Y * scale_factor);
render_size = renpageSize;
return status_t.S_ISOK;
}
private DocPage InitDocPage()
{
DocPage doc_page = new DocPage();
doc_page.BitMap = null;
doc_page.Height = Constants.BLANK_HEIGHT;
doc_page.Width = Constants.BLANK_WIDTH;
doc_page.NativeHeight = Constants.BLANK_HEIGHT;
doc_page.NativeWidth = Constants.BLANK_WIDTH;
doc_page.Content = Page_Content_t.NOTSET;
doc_page.TextBox = null;
doc_page.LinkBox = null;
doc_page.SelHeight = 0;
doc_page.SelWidth = 0;
doc_page.SelX = 0;
doc_page.SelY = 0;
return doc_page;
}
#region Navigation
private void OnBackPageClick(object sender, RoutedEventArgs e)
{
if (m_currpage == 0 || !m_init_done) return;
m_ignorescrollchange = true;
RenderRange(m_currpage - 1, true, zoom_t.NO_ZOOM, 0);
}
private void OnForwardPageClick(object sender, RoutedEventArgs e)
{
if (m_currpage == m_num_pages - 1 || !m_init_done) return;
m_ignorescrollchange = true;
RenderRange(m_currpage + 1, true, zoom_t.NO_ZOOM, 0);
}
private void PageEnterClicked(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == Key.Return)
{
e.Handled = true;
var desired_page = xaml_currPage.Text;
try
{
int page = System.Convert.ToInt32(desired_page);
if (page > 0 && page < (m_num_pages + 1))
{
m_ignorescrollchange = true;
RenderRange(page - 1, true, zoom_t.NO_ZOOM, 0);
}
}
catch (FormatException e1)
{
Console.WriteLine("String is not a sequence of digits.");
}
catch (OverflowException e2)
{
Console.WriteLine("The number cannot fit in an Int32.");
}
}
}
private void OnKeyDownHandler(object sender, System.Windows.Input.KeyEventArgs e)
{
switch (e.Key)
{
case Key.Left:
case Key.PageUp:
if (m_currpage == 0 || !m_init_done)
return;
m_ignorescrollchange = true;
RenderRange(m_currpage - 1, true, zoom_t.NO_ZOOM, 0);
e.Handled = true;
break;
case Key.Right:
case Key.PageDown:
if (m_currpage == m_num_pages - 1 || !m_init_done)
return;
m_ignorescrollchange = true;
RenderRange(m_currpage + 1, true, zoom_t.NO_ZOOM, 0);
e.Handled = true;
break;
case Key.Up:
if (!m_init_done)
return;
e.Handled = true;
OffsetScroll(-Constants.VERT_SCROLL_STEP * m_doczoom);
break;
case Key.Down:
if (!m_init_done)
return;
e.Handled = true;
OffsetScroll(Constants.VERT_SCROLL_STEP * m_doczoom);
break;
}
}
#endregion Navigation
private void CancelLoadClick(object sender, RoutedEventArgs e)
{
/* Cancel during thumbnail loading. Deactivate the button
* and cancel the thumbnail rendering */
if (m_thumbworker != null)
m_thumbworker.CancelAsync();
//xaml_CancelThumb.IsEnabled = false;
}
private void ToggleThumbs(object sender, RoutedEventArgs e)
{
if (m_have_thumbs)
{
if (xaml_ThumbGrid.Visibility == System.Windows.Visibility.Collapsed)
{
xaml_ThumbGrid.Visibility = System.Windows.Visibility.Visible;
}
else
{
xaml_ThumbGrid.Visibility = System.Windows.Visibility.Collapsed;
}
}
}
private void ToggleContents(object sender, RoutedEventArgs e)
{
if (xaml_ContentGrid.Visibility == System.Windows.Visibility.Visible)
{
xaml_ContentGrid.Visibility = System.Windows.Visibility.Collapsed;
return;
}
if (m_num_pages < 0)
return;
if (xaml_ContentList.Items.IsEmpty)
{
int size_content = mu_doc.ComputeContents();
if (size_content == 0)
return;
xaml_ContentList.ItemsSource = mu_doc.contents;
}
xaml_ContentGrid.Visibility = System.Windows.Visibility.Visible;
}
private void ThumbSelected(object sender, MouseButtonEventArgs e)
{
var item = ((FrameworkElement)e.OriginalSource).DataContext as DocPage;
if (item != null)
{
if (item.PageNum < 0)
return;
RenderRange(item.PageNum, true, zoom_t.NO_ZOOM, 0);
}
}
private void ContentSelected(object sender, MouseButtonEventArgs e)
{
var item = ((FrameworkElement)e.OriginalSource).DataContext as ContentItem;
if (item != null && item.Page < m_num_pages)
{
int page = m_docPages[item.Page].PageNum;
if (page >= 0 && page < m_num_pages)
RenderRange(page, true, zoom_t.NO_ZOOM, 0);
}
}
/* We need to avoid rendering due to size changes */
private void ListViewScrollChanged(object sender, ScrollChangedEventArgs e)
{
/* This makes sure we dont call render range a second time due to
* page advances */
int first_item = -1;
int second_item = -1;
//Console.WriteLine("***************************************/n");
//Console.WriteLine("VerticalChange = " + e.VerticalChange + "/n");
//Console.WriteLine("ExtentHeightChange = " + e.ExtentHeightChange + "/n");
//Console.WriteLine("ExtentWidthChange = " + e.ExtentWidthChange + "/n");
//Console.WriteLine("HorizontalChange = " + e.HorizontalChange + "/n");
//Console.WriteLine("ViewportHeightChange = " + e.ViewportHeightChange + "/n");
//Console.WriteLine("ViewportWidthChange = " + e.ViewportWidthChange + "/n");
//Console.WriteLine("ExtentHeight = " + e.ExtentHeight + "/n");
//Console.WriteLine("ViewportHeight = " + e.ViewportHeight + "/n");
//Console.WriteLine("VerticalOffset = " + e.VerticalOffset + "/n");
//Console.WriteLine("***************************************/n");
if (m_ignorescrollchange == true)
{
m_ignorescrollchange = false;
return;
}
if (!m_init_done)
return;
if (e.VerticalChange == 0)
return;
if (m_num_pages == 1)
return;
/* From current page go forward and backward checking if pages are
* visible */
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
if (viewer != null)
{
double bottom = this.ActualHeight;
/* first going forward */
for (int kk = m_currpage + 1; kk < m_num_pages; kk++)
{
UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk);
double y_top = uiElement.TranslatePoint(new System.Windows.Point(0, 0), xaml_PageList).Y;
double y_bottom = uiElement.TranslatePoint(new System.Windows.Point(0, m_docPages[kk].Height), xaml_PageList).Y;
/* Test if this and all further pages are outside window */
if (y_top > bottom)
break;
/* Test if page is not even yet in window */
if (y_bottom > 0)
{
if (!(m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled == true))
{
/* In this case grab the first one that we find */
if (second_item == -1)
second_item = kk;
}
}
}
/* and now going backward */
for (int kk = m_currpage; kk > -1; kk--)
{
UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk);
double y_top = uiElement.TranslatePoint(new System.Windows.Point(0, 0), xaml_PageList).Y;
double y_bottom = uiElement.TranslatePoint(new System.Windows.Point(0, m_docPages[kk].Height), xaml_PageList).Y;
/* Test if this and all further pages are outside window */
if (y_bottom < 0)
break;
if (y_top < bottom)
if (!(m_dispatcherTimer != null && m_dispatcherTimer.IsEnabled == true))
first_item = kk;
}
e.Handled = true;
if (first_item != -1)
second_item = first_item;
/* Finish */
if (m_ScrolledChanged)
{
m_ScrolledChanged = false;
}
else
{
/* We have to update the vertical scroll position */
double perc = (e.VerticalOffset) / (e.ExtentHeight - e.ViewportHeight);
xaml_VerticalScroll.Value = perc * xaml_VerticalScroll.Maximum;
}
if (second_item < 0)
second_item = 0;
RenderRange(second_item, false, zoom_t.NO_ZOOM, 0);
}
}
/* ScrollIntoView will not scroll to top on its own. If item is already
* in view it just sits there */
private void ScrollPageToTop(int k, double offset, bool from_scroller)
{
if (m_num_pages == 1)
return;
/* Get access to the scrollviewer */
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
if (viewer != null)
{
UIElement uiElement = (UIElement) xaml_PageList.ItemContainerGenerator.ContainerFromIndex(k);
double y = uiElement.TranslatePoint(new System.Windows.Point(0, offset), xaml_PageList).Y;
double curr_value = viewer.VerticalOffset;
viewer.ScrollToVerticalOffset(curr_value + y);
if (!from_scroller)
{
double perc = (double) k / (double) ( m_num_pages - 1);
xaml_VerticalScroll.Value = perc * xaml_VerticalScroll.Maximum;
}
}
}
/* Scroll to offset */
private void OffsetScroll(double offset)
{
if (m_num_pages == 1)
return;
/* Get access to the scrollviewer */
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
if (viewer != null)
{
double curr_value = viewer.VerticalOffset;
AdjustScrollPercent(offset / viewer.ScrollableHeight);
viewer.ScrollToVerticalOffset(curr_value + offset);
}
}
/* Scroll to offset */
private void OffsetScrollPercent(double percent)
{
/* Get access to the scrollviewer */
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
if (viewer != null)
{
double curr_value = viewer.VerticalOffset;
if (curr_value < 0 || curr_value > viewer.MaxHeight)
return;
var extentheight = viewer.ExtentHeight - viewer.ViewportHeight;
var pos = extentheight * percent;
viewer.ScrollToVerticalOffset(pos);
}
}
/* Render +/- the look ahead from where we are if blank page is present */
async private void RenderRange(int new_page, bool scrollto, zoom_t newzoom, double zoom_offset)
{
/* Need to figure out what pages are going to be visible */
double bottom = this.ActualHeight;
bool done = false;
int final_page = new_page;
double count = -zoom_offset;
int offset = -1;
bool scrollbottom = false;
if (newzoom != zoom_t.NO_ZOOM)
offset = 0;
if (m_thumbnails.Count < m_num_pages)
final_page = final_page + 1;
else
{
while (!done && final_page >= 0 && final_page < m_num_pages)
{
count = count + m_thumbnails[final_page].NativeHeight * m_doczoom;
final_page = final_page + 1;
if (final_page == m_num_pages || count > bottom)
done = true;
}
/* We have zoomed out to a point where the offset will not stay
* in its current spot. Figure out where we need to be */
final_page = final_page - 1;
if (newzoom == zoom_t.ZOOM_OUT && count < bottom)
{
int curr_page = new_page - 1;
while (true)
{
if (curr_page < 0)
break;
count = count + m_thumbnails[curr_page].NativeHeight * m_doczoom;
if (count > bottom)
break;
curr_page = curr_page - 1;
}
new_page = curr_page;
if (new_page < 0)
new_page = 0;
scrollbottom = true;
}
}
for (int k = new_page + offset; k <= final_page + 1; k++)
{
if (k >= 0 && k < m_num_pages)
{
/* Check if page is already rendered */
var doc = m_docPages[k];
if (doc.Content != Page_Content_t.FULL_RESOLUTION ||
doc.Zoom != m_doczoom || m_AA != doc.AA ||
(doc.Annotate == Annotate_t.UNKNOWN && m_showannot) ||
(doc.Annotate == Annotate_t.ANNOTATE_VISIBLE && !m_showannot) ||
(doc.Annotate == Annotate_t.ANNOTATE_HIDDEN && m_showannot))
{
Point ras_size;
double scale_factor = m_doczoom;
/* To avoid multiple page renderings on top of one
* another with scroll changes mark this as being
* full resolution */
m_docPages[k].Content = Page_Content_t.FULL_RESOLUTION;
/* Avoid launching another thread just because we don't
* know the annotation condition for this page */
m_docPages[k].Annotate = Annotate_t.COMPUTING;
if (ComputePageSize(k, scale_factor, out ras_size) == status_t.S_ISOK)
{
try
{
Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
BlocksText charlist = null;
Annotate_t annot = Annotate_t.UNKNOWN;
m_docPages[k].NativeWidth = (int)(ras_size.X / scale_factor);
m_docPages[k].NativeHeight = (int)(ras_size.Y / scale_factor);
Task ren_task =
new Task(() => mu_doc.RenderPage(k, bitmap,
(int)ras_size.X, (int)ras_size.Y, scale_factor,
false, true, !(m_textset[k]), out charlist, m_showannot,
out annot));
ren_task.Start();
await ren_task.ContinueWith((antecedent) =>
{
status_t code = (status_t)ren_task.Result;
if (code == status_t.S_ISOK)
{
SetPageAnnot(k, annot);
if (m_docPages[k].TextBox != null)
ScaleTextBox(k);
if (m_links_on && m_page_link_list != null)
{
m_docPages[k].LinkBox = m_page_link_list[k];
if (m_docPages[k].LinkBox != null)
ScaleLinkBox(k);
}
else
{
m_docPages[k].LinkBox = null;
}
if (!(m_textset[k]) && charlist != null)
{
m_textptrs[k] = charlist;
if (scale_factor != 1.0)
ScaleTextBlocks(k, scale_factor);
m_docPages[k].TextBlocks = m_textptrs[k];
m_textset[k] = true;
if (m_selectall)
{
int num_blocks = m_docPages[k].TextBlocks.Count;
for (int jj = 0; jj < num_blocks; jj++)
{
m_docPages[k].TextBlocks[jj].Color = m_textselectcolor;
}
}
}
else
{
/* We had to rerender due to scale */
if (m_textptrs[k] != null)
{
ScaleTextBlocks(k, scale_factor);
m_docPages[k].TextBlocks = m_textptrs[k];
}
if (m_lineptrs[k] != null)
{
ScaleTextLines(k, scale_factor);
m_docPages[k].SelectedLines = m_lineptrs[k];
}
}
/* This needs to be handled here to reduce
* flashing effects */
if (newzoom != zoom_t.NO_ZOOM && k == new_page)
{
m_ignorescrollchange = true;
UpdatePageSizes();
xaml_VerticalScroll.Maximum = m_totalpageheight * m_doczoom + 4 * m_num_pages;
if (!scrollbottom)
ScrollPageToTop(new_page, zoom_offset, false);
}
UpdatePage(k, bitmap, ras_size,
Page_Content_t.FULL_RESOLUTION, m_doczoom, m_AA);
if (k == new_page && scrollto && new_page != m_currpage)
{
m_doscroll = true;
ScrollPageToTop(k, 0, false);
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Memory allocation failed page " + k + "\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
}
else
{
/* We did not have to render the page but we may need to
* scroll to it */
if (k == new_page && scrollto && new_page != m_currpage)
{
m_ignorescrollchange = true;
ScrollPageToTop(k, 0, false);
}
}
}
}
/* Release old range and set new page */
//ReleasePages(m_currpage, new_page - 1, final_page + 1);
m_currpage = new_page;
xaml_currPage.Text = (m_currpage + 1).ToString();
}
/* Avoids the next page jumping into view when touched by mouse. See xaml code */
private void AvoidScrollIntoView(object sender, RequestBringIntoViewEventArgs e)
{
if (!m_doscroll)
e.Handled = true;
else
m_doscroll = false;
}
private void ReleasePages(int old_page, int new_page, int final_page)
{
if (old_page == new_page) return;
/* To keep from having memory issue reset the page back to
the thumb if we are done rendering the thumbnails */
for (int k = 0; k < m_num_pages; k++)
{
if (k < new_page || k > final_page)
{
if (k >= 0 && k < m_num_pages)
{
SetThumb(k);
}
}
}
}
/* Return this page from a full res image to the thumb image */
private void SetThumb(int page_num)
{
/* See what is there now */
var doc_page = m_docPages[page_num];
if (doc_page.Content == Page_Content_t.THUMBNAIL &&
doc_page.Zoom == m_doczoom) return;
if (m_thumbnails.Count > page_num)
{
doc_page.Content = Page_Content_t.THUMBNAIL;
doc_page.Zoom = m_doczoom;
doc_page.BitMap = m_thumbnails[page_num].BitMap;
doc_page.Width = (int)(m_doczoom * doc_page.BitMap.PixelWidth / Constants.SCALE_THUMB);
doc_page.Height = (int)(m_doczoom * doc_page.BitMap.PixelHeight / Constants.SCALE_THUMB);
doc_page.PageNum = page_num;
doc_page.LinkBox = null;
doc_page.TextBox = null;
/* No need to refresh unless it just occurs during other stuff
* we just want to make sure we can release the bitmaps */
//doc_page.PageRefresh();
}
}
private void gsDLL(object gsObject, String mess)
{
ShowMessage(NotifyType_t.MESS_STATUS, mess);
}
/* Catastrophic */
private void muDLL(object gsObject, String mess)
{
ShowMessage(NotifyType_t.MESS_ERROR, mess);
/* Disable even the ability to open a file */
xaml_open.Opacity = 0.5;
xaml_open.IsEnabled = false;
xaml_file.Opacity = 0.5;
xaml_file.IsEnabled = false;
/* And to drag - drop or registry start up */
xaml_PageList.RemoveHandler(Grid.DragOverEvent, new System.Windows.DragEventHandler(Grid_DragOver));
xaml_PageList.RemoveHandler(Grid.DropEvent, new System.Windows.DragEventHandler(Grid_Drop));
m_regstartup = false;
}
private void gsIO(object gsObject, String mess, int len)
{
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)
{
xaml_DistillProgress.Value = 100;
xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed;
if (asyncInformation.Params.result == GS_Result_t.gsFAILED)
{
switch (asyncInformation.Params.task)
{
case GS_Task_t.CREATE_XPS:
ShowMessage(NotifyType_t.MESS_STATUS, "Ghostscript failed to create XPS");
break;
case GS_Task_t.PS_DISTILL:
ShowMessage(NotifyType_t.MESS_STATUS, "Ghostscript failed to distill PS");
break;
case GS_Task_t.SAVE_RESULT:
ShowMessage(NotifyType_t.MESS_STATUS, "Ghostscript failed to convert document");
break;
}
return;
}
GSResult(asyncInformation.Params);
}
else
{
this.xaml_DistillProgress.Value = asyncInformation.Progress;
}
}
/* GS Result*/
public void GSResult(gsParams_t gs_result)
{
if (gs_result.result == GS_Result_t.gsCANCELLED)
{
xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed;
return;
}
if (gs_result.result == GS_Result_t.gsFAILED)
{
xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed;
ShowMessage(NotifyType_t.MESS_STATUS, "GS Failed Conversion");
return;
}
switch (gs_result.task)
{
case GS_Task_t.CREATE_XPS:
xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed;
PrintXPS(gs_result.outputfile);
break;
case GS_Task_t.PS_DISTILL:
xaml_DistillGrid.Visibility = System.Windows.Visibility.Collapsed;
m_origfile = gs_result.inputfile;
OpenFile2(gs_result.outputfile);
break;
case GS_Task_t.SAVE_RESULT:
ShowMessage(NotifyType_t.MESS_STATUS, "GS Completed Conversion");
break;
}
}
private void PrintCommand(object sender, ExecutedRoutedEventArgs e)
{
Print(sender, e);
}
/* Printing is achieved using xpswrite device in ghostscript and
* pushing that file through the XPS print queue */
private void Print(object sender, RoutedEventArgs e)
{
if (!m_file_open)
return;
if (m_printcontrol == null)
{
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
m_printcontrol.Show();
return;
}
private void PrintXPS(String file)
{
gsprint ghostprint = new gsprint();
/* We have to create the XPS document on a different thread */
XpsDocument xpsDocument = new XpsDocument(file, FileAccess.Read);
FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence();
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(printq, fixedDocSeq, m_printcontrol);
}
private void PrintProgress(object printHelper, gsPrintEventArgs Information)
{
if (Information.Status != PrintStatus_t.PRINT_BUSY)
{
xaml_PrintProgress.Value = 100;
xaml_PrintGrid.Visibility = System.Windows.Visibility.Collapsed;
}
else
{
xaml_PrintProgress.Value =
100.0 * (double)Information.Page / (double)m_num_pages;
}
}
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;
if (m_ghostscript != null)
m_ghostscript.Cancel();
}
private void CancelPrintClick(object sender, RoutedEventArgs e)
{
m_ghostprint.CancelAsync();
}
private void ShowGSMessage(object sender, RoutedEventArgs e)
{
m_gsoutput.Show();
}
private void ConvertClick(object sender, RoutedEventArgs e)
{
if (m_ghostscript.GetStatus() != gsStatus.GS_READY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "GS busy");
return;
}
if (m_convertwin == null || !m_convertwin.IsActive)
{
m_convertwin = new Convert(m_num_pages);
m_convertwin.ConvertUpdateMain += new Convert.ConvertCallBackMain(ConvertReturn);
m_convertwin.Activate();
m_convertwin.Show();
}
}
private void ConvertReturn(object sender)
{
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;
}
System.Collections.IList pages = m_convertwin.xaml_PageList.SelectedItems;
System.Collections.IList pages_selected = null;
String options = m_convertwin.xaml_options.Text;
int resolution = 72;
bool multi_page_needed = false;
int first_page = -1;
int last_page = -1;
if (pages.Count == 0)
{
ShowMessage(NotifyType_t.MESS_STATUS, "No Pages Selected");
return;
}
/* Get a filename */
System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog();
dlg.Filter = "All files (*.*)|*.*";
dlg.FilterIndex = 1;
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
if (device.MuPDFDevice)
{
/* Allow only one of these as a time */
pages_selected = pages;
var val = m_convertwin.xaml_resolution.Text;
if (val.Length > 0)
{
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;
}
if (mu_doc.ConvertSave(device.DeviceType, dlg.FileName,
pages.Count, pages_selected, resolution) == gsStatus.GS_BUSY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "MuPDF conversion busy");
return;
}
xaml_CancelMuPDF.Visibility = System.Windows.Visibility.Visible;
xaml_MuPDFGrid.Visibility = System.Windows.Visibility.Visible;
}
else
{
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;
}
m_convertwin.Close();
}
return;
}
private void ExtractPages(object sender, RoutedEventArgs e)
{
if (!m_init_done || m_isXPS || m_isImage)
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 */
System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.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)
{
m_password = new Password();
m_password.PassUpdateMain += new Password.PassCallBackMain(PasswordReturn);
m_password.Activate();
m_password.Show();
}
}
private void PasswordReturn(object sender)
{
if (mu_doc.ApplyPassword(m_password.xaml_Password.Password))
{
m_currpassword = m_password.xaml_Password.Password;
m_password.Close();
m_password = null;
xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Visible;
xaml_openfilestatus.Text = "Opening File";
StartViewer();
}
else
{
xaml_OpenProgressGrid.Visibility = System.Windows.Visibility.Collapsed;
ShowMessage(NotifyType_t.MESS_STATUS, "Password Incorrect");
}
}
private void ShowInfo(object sender, RoutedEventArgs e)
{
String Message;
if (m_file_open)
{
String filename;
if (m_origfile != null && (m_document_type == DocumentTypes.PS ||
m_document_type == DocumentTypes.EPS))
filename = m_origfile;
else
filename = m_currfile;
Message =
" File: " + filename + "\n" +
"Document Type: " + m_document_type + "\n" +
" Pages: " + m_num_pages + "\n" +
" Current Page: " + (m_currpage + 1) + "\n";
if (m_infowindow == null || !(m_infowindow.IsActive))
m_infowindow = new Info();
m_infowindow.xaml_TextInfo.Text = Message;
m_infowindow.FontFamily = new FontFamily("Courier New");
m_infowindow.Show();
}
}
#region Zoom Control
/* Find out where the current page is */
private double ComputeOffsetZoomOut(double old_zoom)
{
double y = 0;
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
if (viewer != null)
{
/* Look at the offset and where it falls relative to the top of our current page */
UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(m_currpage);
y = viewer.TranslatePoint(new System.Windows.Point(0, 0), uiElement).Y;
}
return y * m_doczoom / old_zoom;
}
private double ComputeOffsetZoomIn(double old_zoom, out int new_page)
{
double y = 0;
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
new_page = m_currpage;
if (viewer != null)
{
/* Look at the offset and where it falls relative to the top of our current page */
UIElement uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(m_currpage);
y = viewer.TranslatePoint(new System.Windows.Point(0, 0), uiElement).Y;
/* If we are zoomed out, we can be on a page that is not on the top boundry. See if we can find one
* that is */
if (y < 0)
{
new_page = m_currpage - 1;
while (true)
{
if (new_page < 0)
{
new_page = 0;
return 0;
}
uiElement = (UIElement)xaml_PageList.ItemContainerGenerator.ContainerFromIndex(new_page);
y = viewer.TranslatePoint(new System.Windows.Point(0, 0), uiElement).Y;
if (y >= 0)
{
return y * m_doczoom / old_zoom;
}
new_page = new_page - 1;
}
}
}
return y * m_doczoom / old_zoom;
}
private void ZoomOut(object sender, RoutedEventArgs e)
{
if (!m_init_done || m_doczoom <= Constants.ZOOM_MIN)
return;
double old_zoom = m_doczoom;
m_doczoom = m_doczoom - Constants.ZOOM_STEP;
if (m_doczoom < Constants.ZOOM_MIN)
m_doczoom = Constants.ZOOM_MIN;
xaml_ZoomSlider.Value = m_doczoom * 100.0;
double offset = ComputeOffsetZoomOut(old_zoom);
RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset);
}
private void ZoomIn(object sender, RoutedEventArgs e)
{
if (!m_init_done || m_doczoom >= Constants.ZOOM_MAX)
return;
double old_zoom = m_doczoom;
m_doczoom = m_doczoom + Constants.ZOOM_STEP;
if (m_doczoom > Constants.ZOOM_MAX)
m_doczoom = Constants.ZOOM_MAX;
xaml_ZoomSlider.Value = m_doczoom * 100.0;
int newpage;
double offset = ComputeOffsetZoomIn(old_zoom, out newpage);
RenderRange(newpage, false, zoom_t.ZOOM_IN, offset);
}
private void ActualSize(object sender, RoutedEventArgs e)
{
if (!m_init_done)
return;
double old_zoom = m_doczoom;
m_doczoom = 1.0;
xaml_ZoomSlider.Value = m_doczoom * 100.0;
if (old_zoom < 1.0)
{
int new_page;
double offset = ComputeOffsetZoomIn(old_zoom, out new_page);
RenderRange(new_page, false, zoom_t.ZOOM_IN, offset);
}
else if (old_zoom > 1.0)
{
double offset = ComputeOffsetZoomOut(old_zoom);
RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset);
}
}
private void ContScrollFill(object sender, RoutedEventArgs e)
{
if (!m_init_done)
return;
/* Scale our pages based upon the size of scrollviewer */
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
if (viewer == null)
return;
double width = viewer.ViewportWidth;
double page_width = m_thumbnails[m_currpage].NativeWidth;
double scale = width / page_width;
if (scale < Constants.ZOOM_MIN)
scale = Constants.ZOOM_MIN;
if (scale > Constants.ZOOM_MAX)
scale = Constants.ZOOM_MAX;
if (m_doczoom == scale)
return;
double old_zoom = m_doczoom;
m_doczoom = scale;
xaml_ZoomSlider.Value = m_doczoom * 100.0;
if (old_zoom > m_doczoom)
RenderRange(m_currpage, true, zoom_t.ZOOM_OUT, 0);
else
RenderRange(m_currpage, true, zoom_t.ZOOM_IN, 0);
}
private void ExpandFill(object sender, RoutedEventArgs e)
{
if (!m_init_done)
return;
/* Scale our pages based upon the size of scrollviewer */
ScrollViewer viewer = FindScrollViewer(xaml_PageList);
if (viewer == null)
return;
double height = viewer.ViewportHeight;
double width = viewer.ViewportWidth;
double page_height = m_thumbnails[m_currpage].NativeHeight;
double page_width = m_thumbnails[m_currpage].NativeWidth;
double height_scale = height / page_height;
double width_scale = width / page_width;
double scale = Math.Min(height_scale, width_scale);
if (scale < Constants.ZOOM_MIN)
scale = Constants.ZOOM_MIN;
if (scale > Constants.ZOOM_MAX)
scale = Constants.ZOOM_MAX;
if (m_doczoom == scale)
return;
double old_zoom = m_doczoom;
m_doczoom = scale;
xaml_ZoomSlider.Value = m_doczoom * 100.0;
if (old_zoom > m_doczoom)
RenderRange(m_currpage, true, zoom_t.ZOOM_OUT, 0);
else
RenderRange(m_currpage, true, zoom_t.ZOOM_IN, 0);
}
private void ShowFooter(object sender, RoutedEventArgs e)
{
xaml_FooterControl.Visibility = System.Windows.Visibility.Visible;
}
private void HideFooter(object sender, RoutedEventArgs e)
{
xaml_FooterControl.Visibility = System.Windows.Visibility.Collapsed;
}
private void ZoomReleased(object sender, MouseButtonEventArgs e)
{
if (m_init_done)
{
double zoom = xaml_ZoomSlider.Value / 100.0;
if (zoom > Constants.ZOOM_MAX)
zoom = Constants.ZOOM_MAX;
if (zoom < Constants.ZOOM_MIN)
zoom = Constants.ZOOM_MIN;
double old_zoom = zoom;
m_doczoom = zoom;
if (old_zoom > m_doczoom)
{
double offset = ComputeOffsetZoomOut(old_zoom);
RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset);
}
else
{
int new_page;
double offset = ComputeOffsetZoomIn(old_zoom, out new_page);
RenderRange(new_page, false, zoom_t.ZOOM_IN, offset);
}
}
}
/* If the zoom is not equalto 1 then set the zoom to 1 and scoll to this page */
private void PageDoubleClick(object sender, MouseButtonEventArgs e)
{
return; /* Disable this for now */
if (m_doczoom != 1.0)
{
double old_zoom = m_doczoom;
m_doczoom = 1.0;
xaml_Zoomsize.Text = "100";
var item = ((FrameworkElement)e.OriginalSource).DataContext as DocPage;
if (item != null)
{
if (old_zoom > m_doczoom)
{
double offset = ComputeOffsetZoomOut(old_zoom);
RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset);
}
else
{
int new_page;
double offset = ComputeOffsetZoomIn(old_zoom, out new_page);
RenderRange(new_page, false, zoom_t.ZOOM_IN, offset);
}
}
}
}
private void ZoomEnterClicked(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == Key.Return)
{
e.Handled = true;
var desired_zoom = xaml_Zoomsize.Text;
try
{
double zoom = (double)System.Convert.ToInt32(desired_zoom) / 100.0;
if (zoom > Constants.ZOOM_MAX)
zoom = Constants.ZOOM_MAX;
if (zoom < Constants.ZOOM_MIN)
zoom = Constants.ZOOM_MIN;
double old_zoom = m_doczoom;
m_doczoom = zoom;
if (old_zoom > m_doczoom)
{
double offset = ComputeOffsetZoomOut(old_zoom);
RenderRange(m_currpage, false, zoom_t.ZOOM_OUT, offset);
}
else
{
int new_page;
double offset = ComputeOffsetZoomIn(old_zoom, out new_page);
RenderRange(new_page, false, zoom_t.ZOOM_IN, offset);
}
}
catch (FormatException e1)
{
Console.WriteLine("String is not a sequence of digits.");
}
catch (OverflowException e2)
{
Console.WriteLine("The number cannot fit in an Int32.");
}
}
}
/* Rescale the pages based upon the zoom value and the native size */
private void UpdatePageSizes()
{
SetThumbwidth();
for (int k = 0; k > m_num_pages; k++)
{
var thumbpage = m_thumbnails[k];
var page = m_docPages[k];
if (page.Zoom == m_doczoom)
continue;
int scale_zoom = (int)Math.Round((double)page.Height / (double)thumbpage.NativeHeight);
if (scale_zoom != m_doczoom)
{
page.Height = (int)Math.Round(thumbpage.NativeHeight * m_doczoom);
page.Width = (int)Math.Round(thumbpage.NativeWidth * m_doczoom);
}
}
}
#endregion Zoom Control
#region Thumb Rendering
void SetThumbInit(int page_num, Byte[] bitmap, Point ras_size, double zoom_in)
{
/* Three jobs. Store the thumb and possibly update the full page. Also
add to collection of pages. Set up page geometry info (scale of
100 percent ) */
DocPage doc_page = new DocPage();
m_thumbnails.Add(doc_page);
doc_page.Width = (int)ras_size.X;
doc_page.Height = (int)ras_size.Y;
doc_page.NativeWidth = (int)(ras_size.X / Constants.SCALE_THUMB);
doc_page.NativeHeight = (int)(ras_size.Y / Constants.SCALE_THUMB);
m_totalpageheight = m_totalpageheight + doc_page.NativeHeight;
doc_page.Content = Page_Content_t.THUMBNAIL;
doc_page.Zoom = zoom_in;
int stride = doc_page.Width * 4;
doc_page.BitMap = BitmapSource.Create(doc_page.Width, doc_page.Height,
72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride);
doc_page.PageNum = page_num;
/* Lets see if we need to set the main page */
var doc = m_docPages[page_num];
switch (doc.Content)
{
case Page_Content_t.FULL_RESOLUTION:
case Page_Content_t.THUMBNAIL:
return;
case Page_Content_t.NOTSET:
doc_page = InitDocPage();
doc_page.Content = Page_Content_t.THUMBNAIL;
doc_page.Zoom = zoom_in;
doc_page.BitMap = m_thumbnails[page_num].BitMap;
doc_page.Width = (int)(ras_size.X / Constants.SCALE_THUMB);
doc_page.Height = (int)(ras_size.Y / Constants.SCALE_THUMB);
doc_page.PageNum = page_num;
this.m_docPages[page_num] = doc_page;
break;
case Page_Content_t.OLD_RESOLUTION:
return;
}
}
private void ThumbsWork(object sender, DoWorkEventArgs e)
{
Point ras_size;
status_t code;
double scale_factor = Constants.SCALE_THUMB;
BackgroundWorker worker = sender as BackgroundWorker;
Byte[] bitmap;
for (int k = 0; k < m_num_pages; k++)
{
if (ComputePageSize(k, scale_factor, out ras_size) == status_t.S_ISOK)
{
try
{
bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
BlocksText charlist;
Annotate_t annot;
/* Synchronous call on our background thread */
code = (status_t)mu_doc.RenderPage(k, bitmap, (int)ras_size.X,
(int)ras_size.Y, scale_factor, false, false, false,
out charlist, false, out annot);
}
catch (OutOfMemoryException em)
{
Console.WriteLine("Memory allocation failed thumb page " + k + em.Message + "\n");
break;
}
/* Use thumb if we rendered ok */
if (code == status_t.S_ISOK)
{
double percent = 100 * (double)(k + 1) / (double)m_num_pages;
thumb_t curr_thumb = new thumb_t();
curr_thumb.page_num = k;
curr_thumb.bitmap = bitmap;
curr_thumb.size = ras_size;
worker.ReportProgress((int)percent, curr_thumb);
}
}
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
}
}
private void ThumbsCompleted(object sender, RunWorkerCompletedEventArgs e)
{
xaml_ProgressGrid.Visibility = System.Windows.Visibility.Collapsed;
xaml_ThumbProgress.Value = 0;
xaml_ThumbList.ItemsSource = m_thumbnails;
m_have_thumbs = true;
m_thumbworker = null;
//xaml_CancelThumb.IsEnabled = true;
xaml_ThumbList.Items.Refresh();
xaml_VerticalScroll.Minimum = 0;
xaml_VerticalScroll.Maximum = m_totalpageheight + 4 * m_num_pages;
//thumbSize = (viewportSize/(maximum–minimum+viewportSize))×trackLength
SetThumbwidth();
//ScrollBarExtensions.SetThumbLength(xaml_VerticalScroll, 1);
}
private void ThumbsProgressChanged(object sender, ProgressChangedEventArgs e)
{
thumb_t thumb = (thumb_t)(e.UserState);
xaml_ThumbProgress.Value = e.ProgressPercentage;
SetThumbInit(thumb.page_num, thumb.bitmap, thumb.size, 1.0);
}
private void RenderThumbs()
{
/* Create background task for rendering the thumbnails. Allow
this to be cancelled if we open a new doc while we are in loop
rendering. Put the UI updates in the progress changed which will
run on the main thread */
try
{
m_thumbworker = new BackgroundWorker();
m_thumbworker.WorkerReportsProgress = true;
m_thumbworker.WorkerSupportsCancellation = true;
m_thumbworker.DoWork += new DoWorkEventHandler(ThumbsWork);
m_thumbworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ThumbsCompleted);
m_thumbworker.ProgressChanged += new ProgressChangedEventHandler(ThumbsProgressChanged);
xaml_ProgressGrid.Visibility = System.Windows.Visibility.Visible;
m_thumbworker.RunWorkerAsync();
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Memory allocation failed during thumb rendering\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
#endregion Thumb Rendering
#region Copy Paste
/* Copy the current page as a bmp to the clipboard this is done at the
* current resolution */
private void CopyPage(object sender, RoutedEventArgs e)
{
if (!m_init_done)
return;
var curr_page = m_docPages[m_currpage];
System.Windows.Clipboard.SetImage(curr_page.BitMap);
m_clipboardset = true;
}
/* Paste the page to various types supported by the windows encoder class */
private void PastePage(object sender, RoutedEventArgs e)
{
var menu = (System.Windows.Controls.MenuItem)sender;
String tag = (String)menu.Tag;
if (!m_clipboardset || !System.Windows.Clipboard.ContainsImage() ||
!m_init_done)
return;
var bitmap = System.Windows.Clipboard.GetImage();
BitmapEncoder encoder;
System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog();
dlg.FilterIndex = 1;
switch (tag)
{
case "PNG":
dlg.Filter = "PNG Files(*.png)|*.png";
encoder = new PngBitmapEncoder();
break;
case "JPG":
dlg.Filter = "JPEG Files(*.jpg)|*.jpg";
encoder = new JpegBitmapEncoder();
break;
case "WDP":
dlg.Filter = "HDP Files(*.wdp)|*.wdp";
encoder = new WmpBitmapEncoder();
break;
case "TIF":
dlg.Filter = "TIFF Files(*.tif)|*.tif";
encoder = new TiffBitmapEncoder();
break;
case "BMP":
dlg.Filter = "BMP Files(*.bmp)|*.bmp";
encoder = new BmpBitmapEncoder();
break;
case "GIF":
dlg.Filter = "GIF Files(*.gif)|*.gif";
encoder = new GifBitmapEncoder();
break;
default:
return;
}
encoder.Frames.Add(BitmapFrame.Create(bitmap));
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
using (var stream = dlg.OpenFile())
encoder.Save(stream);
}
}
#endregion Copy Paste
#region SaveAs
String CreatePDFXA(Save_Type_t type)
{
Byte[] Resource;
String Profile;
switch (type)
{
case Save_Type_t.PDFA1_CMYK:
case Save_Type_t.PDFA2_CMYK:
Resource = Properties.Resources.PDFA_def;
Profile = m_outputintents.cmyk_icc;
break;
case Save_Type_t.PDFA1_RGB:
case Save_Type_t.PDFA2_RGB:
Resource = Properties.Resources.PDFA_def;
Profile = m_outputintents.rgb_icc;
break;
case Save_Type_t.PDFX3_CMYK:
Resource = Properties.Resources.PDFX_def;
Profile = m_outputintents.cmyk_icc;
break;
case Save_Type_t.PDFX3_GRAY:
Resource = Properties.Resources.PDFX_def;
Profile = m_outputintents.gray_icc;
break;
default:
return null;
}
String Profile_new = Profile.Replace("\\", "/");
String result = System.Text.Encoding.UTF8.GetString(Resource);
String pdfx_cust = result.Replace("ICCPROFILE", Profile_new);
var out_file = System.IO.Path.GetTempFileName();
System.IO.File.WriteAllText(out_file, pdfx_cust);
return out_file;
}
private void SaveFile(Save_Type_t type)
{
if (!m_file_open)
return;
System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog();
dlg.FilterIndex = 1;
/* PDF output types */
if (type <= Save_Type_t.PDF)
{
dlg.Filter = "PDF Files(*.pdf)|*.pdf";
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
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 or mupdf */
System.IO.File.Copy(m_currfile, dlg.FileName, true);
use_gs = false;
break;
case Save_Type_t.LINEAR_PDF:
mu_doc.PDFExtract(m_currfile, dlg.FileName, m_currpassword,
m_currpassword != null, true, -1, null);
use_gs = false;
break;
case Save_Type_t.PDF13:
options = "-dCompatibilityLevel=1.3";
break;
case Save_Type_t.PDFA1_CMYK:
options = "-dPDFA=1 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceCMYK -dColorConversionStrategy=/CMYK -sOutputICCProfile=" + m_outputintents.cmyk_icc;
break;
case Save_Type_t.PDFA1_RGB:
options = "-dPDFA=1 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceRGB -dColorConversionStrategy=/RGB -sOutputICCProfile=" + m_outputintents.rgb_icc;
break;
case Save_Type_t.PDFA2_CMYK:
options = "-dPDFA=2 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceCMYK -dColorConversionStrategy=/CMYK -sOutputICCProfile=" + m_outputintents.cmyk_icc;
break;
case Save_Type_t.PDFA2_RGB:
options = "-dPDFA=2 -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceRGB -dColorConversionStrategy=/RGB -sOutputICCProfile=" + m_outputintents.rgb_icc;
break;
case Save_Type_t.PDFX3_CMYK:
options = "-dPDFX -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceCMYK -dColorConversionStrategy=/CMYK -sOutputICCProfile=" + m_outputintents.cmyk_icc;
break;
case Save_Type_t.PDFX3_GRAY:
options = "-dPDFX -dNOOUTERSAVE -dPDFACompatibilityPolicy=1 -sProcessColorModel=DeviceGray -dColorConversionStrategy=/Gray -sOutputICCProfile=" + m_outputintents.cmyk_icc;
break;
}
if (use_gs)
{
xaml_DistillProgress.Value = 0;
if (m_ghostscript.Convert(m_currfile, options,
Enum.GetName(typeof(gsDevice_t), gsDevice_t.pdfwrite),
dlg.FileName, m_num_pages, 300, false, null, -1, -1,
init_file, null) == gsStatus.GS_BUSY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "GS busy");
return;
}
xaml_DistillName.Text = "Creating PDF";
xaml_CancelDistill.Visibility = System.Windows.Visibility.Collapsed;
xaml_DistillName.FontWeight = FontWeights.Bold;
xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible;
}
}
}
else
{
/* Non PDF output */
gsDevice_t Device = gsDevice_t.xpswrite;
bool use_mupdf = true;
String Message = "";
textout_t textout = textout_t.HTML;
switch (type)
{
case Save_Type_t.HTML:
dlg.Filter = "HTML (*.html)|*.html";
Message = "HTML content written";
break;
case Save_Type_t.XML:
dlg.Filter = "XML (*.xml)|*.xml";
Message = "XML content written";
textout = textout_t.XML;
break;
case Save_Type_t.TEXT:
dlg.Filter = "Text (*.txt)|*.txt";
Message = "Text content written";
textout = textout_t.TEXT;
break;
case Save_Type_t.PCLXL:
use_mupdf = false;
dlg.Filter = "PCL-XL (*.bin)|*.bin";
Device = gsDevice_t.pxlcolor;
break;
case Save_Type_t.XPS:
use_mupdf = false;
dlg.Filter = "XPS Files(*.xps)|*.xps";
break;
}
if (!use_mupdf)
{
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
if (m_ghostscript.Convert(m_currfile, "",
Enum.GetName(typeof(gsDevice_t), Device),
dlg.FileName, 1, 300, false, null, -1, -1,
null, null) == gsStatus.GS_BUSY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "GS busy");
return;
}
}
}
else
{
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
/* Write out first non null page then append the rest */
int curr_page = 0;
bool done = false;
while (!done)
{
String output = null;
output = mu_doc.GetText(curr_page, textout);
if (output == null)
{
curr_page = curr_page + 1;
if (curr_page == m_num_pages)
{
ShowMessage(NotifyType_t.MESS_STATUS, "No text found in file");
return;
}
}
else
{
System.IO.File.WriteAllText(dlg.FileName, output);
done = true;
}
}
curr_page = curr_page + 1;
if (curr_page == m_num_pages)
{
ShowMessage(NotifyType_t.MESS_STATUS, Message);
return;
}
done = false;
while (!done)
{
String output = null;
output = mu_doc.GetText(curr_page, textout);
if (output != null)
{
System.IO.File.AppendAllText(dlg.FileName, output);
}
curr_page = curr_page + 1;
if (curr_page == m_num_pages)
{
ShowMessage(NotifyType_t.MESS_STATUS, Message);
return;
}
}
}
}
}
}
private void SaveSVG(object sender, RoutedEventArgs e)
{
SaveFile(Save_Type_t.SVG);
}
private void SavePDF(object sender, RoutedEventArgs e)
{
SaveFile(Save_Type_t.PDF);
}
private void SaveText(object sender, RoutedEventArgs e)
{
SaveFile(Save_Type_t.TEXT);
}
private void SaveXML(object sender, RoutedEventArgs e)
{
SaveFile(Save_Type_t.XML);
}
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)
{
SaveFile(Save_Type_t.PDF13);
}
private void SavePDFX3_Gray(object sender, RoutedEventArgs e)
{
if (m_outputintents.gray_icc == null)
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set Gray Output Intent ICC Profile");
return;
}
SaveFile(Save_Type_t.PDFX3_GRAY);
}
private void SavePDFX3_CMYK(object sender, RoutedEventArgs e)
{
if (m_outputintents.cmyk_icc == null)
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile");
return;
}
SaveFile(Save_Type_t.PDFX3_CMYK);
}
private void SavePDFA1_RGB(object sender, RoutedEventArgs e)
{
if (m_outputintents.rgb_icc == null)
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set RGB Output Intent ICC Profile");
return;
}
SaveFile(Save_Type_t.PDFA1_RGB);
}
private void SavePDFA1_CMYK(object sender, RoutedEventArgs e)
{
if (m_outputintents.cmyk_icc == null)
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile");
return;
}
SaveFile(Save_Type_t.PDFA1_CMYK);
}
private void SavePDFA2_RGB(object sender, RoutedEventArgs e)
{
if (m_outputintents.rgb_icc == null)
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set RGB Output Intent ICC Profile");
return;
}
SaveFile(Save_Type_t.PDFA2_RGB);
}
private void SavePDFA2_CMYK(object sender, RoutedEventArgs e)
{
if (m_outputintents.cmyk_icc == null)
{
ShowMessage(NotifyType_t.MESS_STATUS, "Set CMYK Output Intent ICC Profile");
return;
}
SaveFile(Save_Type_t.PDFA2_CMYK);
}
private void SavePCLXL(object sender, RoutedEventArgs e)
{
SaveFile(Save_Type_t.PCLXL);
}
private void SaveXPS(object sender, RoutedEventArgs e)
{
SaveFile(Save_Type_t.XPS);
}
#endregion SaveAs
#region Extract
private void Extract(Extract_Type_t type)
{
if (m_selection != null || !m_init_done)
return;
m_selection = new Selection(m_currpage + 1, m_doczoom, type);
m_selection.UpdateMain += new Selection.CallBackMain(SelectionMade);
m_selection.Show();
m_selection.xaml_Image.Source = m_docPages[m_currpage].BitMap;
m_selection.xaml_Image.Height = m_docPages[m_currpage].Height;
m_selection.xaml_Image.Width = m_docPages[m_currpage].Width;
}
async private void SelectionZoom(int page_num, double zoom)
{
Point ras_size;
if (ComputePageSize(page_num, zoom, out ras_size) == status_t.S_ISOK)
{
try
{
Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4];
BlocksText charlist;
Annotate_t annot;
Task ren_task =
new Task(() => mu_doc.RenderPage(page_num, bitmap,
(int)ras_size.X, (int)ras_size.Y, zoom, false, true,
false, out charlist, true, out annot));
ren_task.Start();
await ren_task.ContinueWith((antecedent) =>
{
status_t code = (status_t)ren_task.Result;
if (code == status_t.S_ISOK)
{
if (m_selection != null)
{
int stride = (int)ras_size.X * 4;
m_selection.xaml_Image.Source = BitmapSource.Create((int)ras_size.X, (int)ras_size.Y, 72, 72, PixelFormats.Pbgra32, BitmapPalettes.Halftone256, bitmap, stride);
m_selection.xaml_Image.Height = (int)ras_size.Y;
m_selection.xaml_Image.Width = (int)ras_size.X;
m_selection.UpdateRect();
m_selection.m_curr_state = SelectStatus_t.OK;
}
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
catch (OutOfMemoryException e)
{
Console.WriteLine("Memory allocation failed page " + page_num + "\n");
ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message);
}
}
}
private void SelectionMade(object gsObject, SelectEventArgs results)
{
switch (results.State)
{
case SelectStatus_t.CANCEL:
case SelectStatus_t.CLOSE:
m_selection = null;
return;
case SelectStatus_t.SELECT:
/* Get the information we need */
double zoom = results.ZoomFactor;
Point start = results.TopLeft;
Point size = results.Size;
int page = results.PageNum;
gsDevice_t Device = gsDevice_t.pdfwrite;
start.X = start.X / zoom;
start.Y = start.Y / zoom;
size.X = size.X / zoom;
size.Y = size.Y / zoom;
/* Do the actual extraction */
String options;
System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog();
dlg.FilterIndex = 1;
/* Get us set up to do a fixed size */
options = "-dFirstPage=" + page + " -dLastPage=" + page +
" -dDEVICEWIDTHPOINTS=" + size.X + " -dDEVICEHEIGHTPOINTS=" +
size.Y + " -dFIXEDMEDIA";
/* Set up the translation */
String init_string = "<> setpagedevice";
switch (results.Type)
{
case Extract_Type_t.PDF:
dlg.Filter = "PDF Files(*.pdf)|*.pdf";
break;
case Extract_Type_t.EPS:
dlg.Filter = "EPS Files(*.eps)|*.eps";
Device = gsDevice_t.eps2write;
break;
case Extract_Type_t.PS:
dlg.Filter = "PostScript Files(*.ps)|*.ps";
Device = gsDevice_t.ps2write;
break;
case Extract_Type_t.SVG:
dlg.Filter = "SVG Files(*.svg)|*.svg";
break;
}
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
if (m_ghostscript.Convert(m_currfile, options,
Enum.GetName(typeof(gsDevice_t), Device),
dlg.FileName, 1, 300, false, null, page, page,
null, init_string) == gsStatus.GS_BUSY)
{
ShowMessage(NotifyType_t.MESS_STATUS, "GS busy");
return;
}
}
m_selection.Close();
break;
case SelectStatus_t.ZOOMIN:
/* Render new page at this resolution and hand it off */
SelectionZoom(results.PageNum - 1, results.ZoomFactor);
break;
case SelectStatus_t.ZOOMOUT:
/* Render new page at this resolution and hand it off */
SelectionZoom(results.PageNum - 1, results.ZoomFactor);
break;
}
}
private void ExtractPDF(object sender, RoutedEventArgs e)
{
Extract(Extract_Type_t.PDF);
}
private void ExtractEPS(object sender, RoutedEventArgs e)
{
Extract(Extract_Type_t.EPS);
}
private void ExtractPS(object sender, RoutedEventArgs e)
{
Extract(Extract_Type_t.PS);
}
private void OutputIntents(object sender, RoutedEventArgs e)
{
m_outputintents.Show();
}
#endregion Extract
#region Search
/* Search related code */
private void Search(object sender, RoutedEventArgs e)
{
if (!m_init_done || (m_textsearch != null && m_textsearch.IsBusy))
return;
m_textsearch = null; /* Start out fresh */
if (xaml_SearchControl.Visibility == System.Windows.Visibility.Collapsed)
xaml_SearchControl.Visibility = System.Windows.Visibility.Visible;
else
{
xaml_SearchControl.Visibility = System.Windows.Visibility.Collapsed;
xaml_SearchGrid.Visibility = System.Windows.Visibility.Collapsed;
ClearTextSearch();
}
}
private void OnSearchBackClick(object sender, RoutedEventArgs e)
{
String textToFind = xaml_SearchText.Text;
TextSearchSetUp(-1, textToFind);
}
private void OnSearchForwardClick(object sender, RoutedEventArgs e)
{
String textToFind = xaml_SearchText.Text;
TextSearchSetUp(1, textToFind);
}
/* The thread that is actually doing the search work */
void SearchWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
List