diff options
author | Michael Vrhel <michael.vrhel@artifex.com> | 2014-02-10 09:51:04 -0800 |
---|---|---|
committer | Michael Vrhel <michael.vrhel@artifex.com> | 2014-09-09 16:39:29 -0700 |
commit | e16c621b9a49cc386b3b65e7fde1f25eb780e85b (patch) | |
tree | 7b5e09f9a11e69f7c1e2591af49b1e16f93ec36c /platform/winrt/gsview | |
parent | 6caf1b523606ce3b282d0dfa45da455867d84429 (diff) | |
download | mupdf-e16c621b9a49cc386b3b65e7fde1f25eb780e85b.tar.xz |
Significant amount of content needed for gsview
This includes the interface to ghostscript for creating pdf files from ps
for mupdf to then render in the viewer as well as the capability to print
the output of xpswrite through the windows print queue. Added thumb
viewing and navigation as well as navigation through the table of contents.
To do. Add in password handling, Text Search, Hyperlinks, GS conversion to
other file formats, MuPDF save as other file formats, Page extractions,
proper page selection for printing, Zooming (rescale), Fix the page ranges
that are displayed at full resolution during navigation.
Diffstat (limited to 'platform/winrt/gsview')
30 files changed, 2708 insertions, 61 deletions
diff --git a/platform/winrt/gsview/ContentEntry.cs b/platform/winrt/gsview/ContentEntry.cs new file mode 100644 index 00000000..68600170 --- /dev/null +++ b/platform/winrt/gsview/ContentEntry.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace gsview +{ + public class ContentEntry + { + public String Name + { + get; + set; + } + + public int PageNum + { + get; + set; + } + + public ContentEntry(String Name, int PageNum) + { + this.Name = Name; + this.PageNum = PageNum; + } + }; +} + diff --git a/platform/winrt/gsview/ContentItem.cs b/platform/winrt/gsview/ContentItem.cs new file mode 100644 index 00000000..a9e079c8 --- /dev/null +++ b/platform/winrt/gsview/ContentItem.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel; + +namespace gsview +{ + class ContentItem : INotifyPropertyChanged + { + + public int Page + { + get; + internal set; + } + + public String StringMargin + { + get; + internal set; + } + + public ContentItem() + { + StringMargin = ""; + Page = 0; + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void ContentRefresh() + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs("StringMargin")); + PropertyChanged(this, new PropertyChangedEventArgs("Page")); + } + } + } +} diff --git a/platform/winrt/gsview/Convert.xaml b/platform/winrt/gsview/Convert.xaml new file mode 100644 index 00000000..68a007d2 --- /dev/null +++ b/platform/winrt/gsview/Convert.xaml @@ -0,0 +1,113 @@ +<Window x:Class="gsview.Convert" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + Title="Ghostscript Convert" Height="215.96" Width="440.424"> + + <DockPanel LastChildFill="True"> + + <!-- Device viewer/selector --> + <Grid x:Name="xaml_DeviceGrid" Width="100" Background="DarkGray" DockPanel.Dock="Left" Visibility="Visible" > + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="*" /> + </Grid.RowDefinitions> + <TextBlock Grid.Column="0" Grid.Row="0" Margin="15,0,0,0"> + <Bold>Devices:</Bold> + </TextBlock> + + <ListView Grid.Column="0" Grid.Row="1" x:Name="xaml_DeviceList" HorizontalAlignment="Stretch" + ScrollViewer.CanContentScroll="False" + Background="White" ScrollViewer.PanningMode="Both" Margin="10,5,10,10" SelectionMode="Single"> + <ListView.ItemTemplate> + <DataTemplate> + <StackPanel Margin="5,5,0,0" HorizontalAlignment="Left"> + <TextBlock TextWrapping="Wrap" Text="{Binding DeviceName}" FontFamily="Segoe UI" FontSize="11" /> + </StackPanel> + </DataTemplate> + </ListView.ItemTemplate> + </ListView> + </Grid> + + <Grid x:Name="xaml_PageGrid" Width="100" Background="DarkGray" DockPanel.Dock="Left" Visibility="Visible"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="*" /> + </Grid.RowDefinitions> + <TextBlock Grid.Column="0" Grid.Row="0" Margin="15,0,0,0"> + <Bold>Pages:</Bold> + </TextBlock> + <ListView Grid.Column="0" Grid.Row="1" x:Name="xaml_PageList" HorizontalAlignment="Stretch" + ScrollViewer.CanContentScroll="False" + Background="White" ScrollViewer.PanningMode="Both" Margin="10,5,10,10"> + <ListView.ItemTemplate> + <DataTemplate> + <StackPanel Margin="5,5,0,0" HorizontalAlignment="Left"> + <TextBlock TextWrapping="Wrap" Text="{Binding PageString}" FontFamily="Segoe UI" FontSize="11" /> + </StackPanel> + </DataTemplate> + </ListView.ItemTemplate> + </ListView> + </Grid> + + <!-- Buttons and extra options --> + <Grid Background="DarkGray" DockPanel.Dock="Left"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + + <Grid Grid.Column="0" Grid.Row="0" Background="DarkGray"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + + <Grid Background="DarkGray" Grid.Row="0" Grid.Column="0" Margin="30,15,0,0"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + + <Button Grid.Column="0" Grid.Row="0" Width="50" Height="20" Name="xaml_Convert" Click="ConvertClick" Margin="0,0,0,0"> + <TextBlock>Convert</TextBlock> + </Button> + <Button Grid.Column="0" Grid.Row="1" Width="50" Height="20" Name="xaml_Cancel" Click="ConvertCancel" Margin="0,5,0,0"> + <TextBlock>Cancel</TextBlock> + </Button> + <Button Grid.Column="0" Grid.Row="2" Width="50" Height="20" Name="xaml_HelpConvert" Click="HelpConvert" Margin="0,5,0,0"> + <TextBlock>Help</TextBlock> + </Button> + </Grid> + + + <Grid Background="DarkGray" Grid.Row="0" Grid.Column="1" Margin="25,15,0,0"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + <RowDefinition Height="Auto" /> + </Grid.RowDefinitions> + + <Button Grid.Column="0" Grid.Row="0" Width="70" Height="20" Name="xaml_AllPages" Click="AllPages" Margin="0,0,0,0"> + <TextBlock>All Pages</TextBlock> + </Button> + <Button Grid.Column="0" Grid.Row="1" Width="70" Height="20" Name="xaml_EvenPages" Click="EvenPages" Margin="0,5,0,0"> + <TextBlock>Even Pages</TextBlock> + </Button> + <Button Grid.Column="0" Grid.Row="2" Width="70" Height="20" Name="xaml_OddPages" Click="OddPages" Margin="0,5,0,0"> + <TextBlock>Odd Pages</TextBlock> + </Button> + </Grid> + </Grid> + + + <TextBlock Grid.Column="0" Grid.Row="1" Margin="5,10,0,0"> + <Bold>Options:</Bold> + </TextBlock> + <TextBox Grid.Column="0" Grid.Row="2" Background="White" Height="40" Margin="5,5,5,5" Text=""></TextBox> + </Grid> + + + </DockPanel> +</Window> diff --git a/platform/winrt/gsview/Convert.xaml.cs b/platform/winrt/gsview/Convert.xaml.cs new file mode 100644 index 00000000..30c1b465 --- /dev/null +++ b/platform/winrt/gsview/Convert.xaml.cs @@ -0,0 +1,170 @@ +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 class Device : INotifyPropertyChanged + { + public String DeviceName + { + get; + internal set; + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void PageRefresh() + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs("DeviceName")); + } + } + + public Device() + { + this.DeviceName = ""; + } + }; + + public class SelectPage : INotifyPropertyChanged + { + public int Page + { + get; + internal set; + } + + public int PageString + { + get; + internal set; + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void PageRefresh() + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs("Page")); + } + } + }; + + + /// <summary> + /// Interaction logic for Convert.xaml + /// </summary> + public partial class Convert : Window + { + List<Device> GSDevices; + List<SelectPage> ConvertPages; + public Convert(int num_pages) + { + InitializeComponent(); + GSDevices = new List<Device>(); + ConvertPages = new List<SelectPage>(); + SetDeviceList(); + SetPageList(num_pages); + xaml_DeviceList.ItemsSource = GSDevices; + xaml_PageList.ItemsSource = ConvertPages; + } + + public void SetDeviceList() + { + foreach (gsDevice_t device in Enum.GetValues(typeof(gsDevice_t))) + { + Device device_t = new Device(); + device_t.DeviceName = Enum.GetName(typeof(gsDevice_t), device); + GSDevices.Add(device_t); + } + } + + 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; + ConvertPages.Add(Spage); + } + } + + private void ConvertClick(object sender, RoutedEventArgs e) + { + + } + + private void ConvertCancel(object sender, RoutedEventArgs e) + { + + } + + private void HelpConvert(object sender, RoutedEventArgs e) + { + + } + + private void AllPages(object sender, RoutedEventArgs e) + { + xaml_PageList.SelectAll(); + } + + 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 < ConvertPages.Count; kk = kk + 2) + (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = true; + } + else + { + /* Turn off any odds */ + for (int kk = 0; kk < ConvertPages.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 < ConvertPages.Count; kk = kk + 2) + (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = true; + } + else + { + /* Turn off any evens */ + for (int kk = 1; kk < ConvertPages.Count; kk = kk + 2) + (xaml_PageList.ItemContainerGenerator.ContainerFromIndex(kk) as ListViewItem).IsSelected = false; + } + } + } +} diff --git a/platform/winrt/gsview/DocPage.cs b/platform/winrt/gsview/DocPage.cs new file mode 100644 index 00000000..1cf55112 --- /dev/null +++ b/platform/winrt/gsview/DocPage.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel; +using System.Windows.Media.Imaging; +using System.Collections.ObjectModel; +using System.Windows.Media; + +namespace gsview +{ + public class DocPage : INotifyPropertyChanged + { + public int Height + { + get; + internal set; + } + + public int Width + { + get; + internal set; + } + + + public int NativeHeight + { + get; + set; + } + + public int NativeWidth + { + get; + set; + } + + public double Zoom + { + get; + set; + } + + public BitmapSource BitMap + { + get; + set; + } + + public List<RectList> TextBox + { + get; + set; + } + + public List<RectList> LinkBox + { + get; + set; + } + + public Page_Content_t Content + { + get; + set; + } + + public String PageName + { + get; + set; + } + + public int PageNum + { + get; + set; + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void PageRefresh() + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs("BitMap")); + PropertyChanged(this, new PropertyChangedEventArgs("Height")); + PropertyChanged(this, new PropertyChangedEventArgs("Width")); + PropertyChanged(this, new PropertyChangedEventArgs("TextBox")); + } + } + + public DocPage() + { + this.Height = 0; + this.Width = 0; + this.NativeHeight = 0; + this.NativeWidth = 0; + this.Zoom = 0; + this.BitMap = null; + this.TextBox = null; + this.LinkBox = null; + this.Content = Page_Content_t.NOTSET; + this.PageNum = -1; + this.PageName = ""; + } + + public DocPage(int Height, int Width, double Zoom, BitmapSource BitMap, + List<RectList> TextBox, List<RectList> LinkBox, + Page_Content_t Content, int PageNum) + { + this.Height = Height; + this.Width = Width; + this.Zoom = Zoom; + this.BitMap = BitMap; + this.TextBox = TextBox; + this.LinkBox = LinkBox; + this.Content = Content; + this.PageNum = PageNum; + this.PageName = ("Page " + (PageNum + 1)); + } + }; + public class Pages : ObservableCollection<DocPage> + { + public Pages() + : base() + { + } + } +} diff --git a/platform/winrt/gsview/Links.cs b/platform/winrt/gsview/Links.cs new file mode 100644 index 00000000..822176d8 --- /dev/null +++ b/platform/winrt/gsview/Links.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; + +namespace gsview +{ + public enum link_t + { + LINK_GOTO = 0, + LINK_URI, + TEXTBOX, /* Do double duty with this class */ + NOT_SET, + }; + + class Links + { + link_t type; + //PointF upper_left; + //PointF lower_right; + Uri uri; + int page_num; + + public Links() + { + uri = new Uri(""); + page_num = -1; + type = link_t.NOT_SET; + } + } +} diff --git a/platform/winrt/gsview/MainWindow.xaml b/platform/winrt/gsview/MainWindow.xaml index 5706c547..47a1ef25 100644 --- a/platform/winrt/gsview/MainWindow.xaml +++ b/platform/winrt/gsview/MainWindow.xaml @@ -1,17 +1,74 @@ <Window x:Class="gsview.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - Title="gsview" Height="350" Width="525"> -<!-- To do add in command short cuts and bindings --> - <Grid> - <Menu IsMainMenu="True"> + Title="gsview" Height="800" Width="650"> + + <Window.Resources> + <DataTemplate x:Key="PageTemplate"> + <Image Width="{Binding Width}" Height="{Binding Height}" Stretch="Fill" HorizontalAlignment="Center" Source="{Binding BitMap}" Margin="24,24,0,0"> + <Image.BitmapEffect> + <DropShadowBitmapEffect Color="Black" Direction="-50" + ShadowDepth="40" Softness=".7" /> + </Image.BitmapEffect> + </Image> + </DataTemplate> + + <Style TargetType="{x:Type Button}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Button}"> + <ControlTemplate.Triggers> + <Trigger Property="IsPressed" Value="True"> + <Setter Property="Background" Value="Black" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Customize listview to turn off selection --> + <Style TargetType="{x:Type ListViewItem}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ListViewItem}"> + <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true"> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> + </Border> + <ControlTemplate.Triggers> + <Trigger Property="IsSelected" Value="true"> + <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/> + </Trigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="IsSelected" Value="true"/> + <Condition Property="Selector.IsSelectionActive" Value="false"/> + </MultiTrigger.Conditions> + <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/> + </MultiTrigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + </Window.Resources> + + <!-- To do add in command short cuts and bindings --> + <DockPanel LastChildFill="True"> + <!-- Menu item at top --> + <Menu IsMainMenu="True" DockPanel.Dock="Top"> <MenuItem Header="_File"> <MenuItem Header="_Open..." Click="OpenFile"> <MenuItem.Icon> <Image Source="Resources/OpenFile.png" /> </MenuItem.Icon> </MenuItem> - <MenuItem Header="Save As..." > + <MenuItem Header="MuPDF Save As..." > <MenuItem.Icon> <Image Source="Resources/saveHS.png" /> </MenuItem.Icon> @@ -20,14 +77,14 @@ <MenuItem.Icon> <Image Source="Resources/Close.ico" /> </MenuItem.Icon> - </MenuItem> + </MenuItem> <MenuItem Header="Info"> <MenuItem.Icon> <Image Source="Resources/info.png" /> </MenuItem.Icon> </MenuItem> <Separator /> - <MenuItem Header="Convert..." > + <MenuItem Header="Ghostscript Convert..." Click="ConvertClick"> </MenuItem> <MenuItem Header="Extract..." > </MenuItem> @@ -40,7 +97,7 @@ </MenuItem.Icon> </MenuItem> <Separator /> - <MenuItem Header="Show Messages"> + <MenuItem Header="Show Messages" Click="ShowGSMessage"> <MenuItem.Icon> <Image Source="Resources/Message.png" /> </MenuItem.Icon> @@ -70,18 +127,306 @@ <MenuItem Header="Previous Page" /> <MenuItem Header="Goto Page" /> </MenuItem> + <MenuItem Header="_Options"> + <MenuItem Header="Ghostscript" /> + <MenuItem Header="Color" /> + </MenuItem> + <MenuItem Header="_Window" /> + <MenuItem Header="_Help" /> + </Menu> + + <!-- List of icons for page navigation, print, etc --> + <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Background="WhiteSmoke"> + <Button Width="20" Height="20" Name="BackPage" Click="OnBackPageClick" Background="Transparent" BorderBrush="Transparent" Margin="5,0,5,0"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Ellipse> + <Ellipse.Fill > + <ImageBrush ImageSource="Resources/Left.ico"/> + </Ellipse.Fill> + </Ellipse> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Width="20" Height="20" Name="ForwardPage2" Click="OnForwardPageClick" Background="Transparent" BorderBrush="Transparent"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Ellipse> + <Ellipse.Fill > + <ImageBrush ImageSource="Resources/Right.ico"/> + </Ellipse.Fill> + </Ellipse> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Margin="10 0 0 0" Width="20" Height="20" Click="ZoomIn" Background="Transparent" BorderBrush="Transparent"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Ellipse> + <Ellipse.Fill > + <ImageBrush ImageSource="Resources/zoom_in.ico"/> + </Ellipse.Fill> + </Ellipse> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Margin="10 0 0 0" Width="20" Height="20" Click="ZoomOut" Background="Transparent" BorderBrush="Transparent"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Ellipse> + <Ellipse.Fill > + <ImageBrush ImageSource="Resources/zoom_out.ico"/> + </Ellipse.Fill> + </Ellipse> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Margin="10 0 0 0" Width="20" Height="20" Click="ToggleThumbs" Background="Transparent" BorderBrush="Transparent"> + <Button.ToolTip> + <TextBlock Text="Thumbnails"/> + </Button.ToolTip> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Ellipse> + <Ellipse.Fill > + <ImageBrush ImageSource="Resources/thumbnail.ico"/> + </Ellipse.Fill> + </Ellipse> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Margin="10 0 0 0" Width="20" Height="20" Click="ToggleContents" Background="Transparent" BorderBrush="Transparent"> + <Button.ToolTip> + <TextBlock Text="Contents"/> + </Button.ToolTip> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Width="20" Height="20"> + <Rectangle.Fill> + <ImageBrush ImageSource="Resources/contents.ico"/> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Margin="10 0 0 0" Width="20" Height="20" Click="Search" Background="Transparent" BorderBrush="Transparent"> + <Button.ToolTip> + <TextBlock Text="Search"/> + </Button.ToolTip> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Width="20" Height="20"> + <Rectangle.Fill> + <ImageBrush ImageSource="Resources/search.png"/> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Margin="10 0 0 0" Width="20" Height="20" Click="LinksToggle" Background="Transparent" BorderBrush="Transparent"> + <Button.ToolTip> + <TextBlock Text="Hyperlinks"/> + </Button.ToolTip> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Ellipse> + <Ellipse.Fill > + <ImageBrush ImageSource="Resources/hyperlink.png"/> + </Ellipse.Fill> + </Ellipse> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + <Button Margin="10 0 0 0" Width="20" Height="20" Click="Print" Background="Transparent" BorderBrush="Transparent"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Width="20" Height="20"> + <Rectangle.Fill> + <ImageBrush ImageSource="Resources/printer.ico"/> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + </Button> + </StackPanel> + <!-- The progress bar that runs while the thumbnails are rendered --> + <Grid x:Name="xaml_ProgressGrid" DockPanel.Dock="Bottom" Visibility="Collapsed"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + <ProgressBar x:Name="xaml_ThumbProgress" Grid.Row="0" Grid.Column="0" Margin="3" Minimum="0" + Maximum="100" Height="20" HorizontalAlignment="Stretch" /> + <TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="5, 0, 5, 0"><Bold>Creating Thumbs</Bold></TextBlock> + <Button Grid.Row="0" Grid.Column="2" Width="50" Height="20" Name="xaml_CancelThumb" Click="CancelLoadClick" Background="Transparent" BorderBrush="Transparent" Margin="5,0,5,0"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Height="Auto" RadiusX="5" RadiusY="5"> + <Rectangle.Fill > + <SolidColorBrush Color="LightSlateGray"></SolidColorBrush> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + <TextBlock><Bold>Cancel</Bold></TextBlock> + </Button> + </Grid> + <!-- The progress bar that runs during text search --> + <Grid x:Name="xaml_SearchGrid" DockPanel.Dock="Bottom" Visibility="Collapsed"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + <ProgressBar x:Name="xaml_SearchProgress" Grid.Row="0" Grid.Column="0" Margin="3" Minimum="0" + Maximum="100" Height="20" HorizontalAlignment="Stretch" /> + <TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="5, 0, 5, 0"><Bold>Searching</Bold></TextBlock> + <Button Grid.Row="0" Grid.Column="2" Width="50" Height="20" Name="xaml_CancelSearch" Click="CancelSearchClick" Background="Transparent" BorderBrush="Transparent" Margin="5,0,5,0"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Height="Auto" RadiusX="5" RadiusY="5"> + <Rectangle.Fill > + <SolidColorBrush Color="LightSlateGray"></SolidColorBrush> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + <TextBlock><Bold>Cancel</Bold></TextBlock> + </Button> + </Grid> + + <!-- The progress bar that runs during printing --> + <Grid x:Name="xaml_PrintGrid" DockPanel.Dock="Bottom" Visibility="Collapsed"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + <ProgressBar x:Name="xaml_PrintProgress" Grid.Row="0" Grid.Column="0" Margin="3" Minimum="0" + Maximum="100" Height="20" HorizontalAlignment="Stretch" /> + <TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="5, 0, 5, 0"><Bold>Printing</Bold></TextBlock> + <Button Grid.Row="0" Grid.Column="2" Width="50" Height="20" Name="xaml_CancelPrint" Click="CancelPrintClick" Background="Transparent" BorderBrush="Transparent" Margin="5,0,5,0"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Height="Auto" RadiusX="5" RadiusY="5"> + <Rectangle.Fill > + <SolidColorBrush Color="LightSlateGray"></SolidColorBrush> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + <TextBlock><Bold>Cancel</Bold></TextBlock> + </Button> + </Grid> - <MenuItem Header="_Window" /> - <MenuItem Header="_Help" /> - </Menu> - + <!-- The progress bar that runs during distilling --> + <Grid x:Name="xaml_DistillGrid" DockPanel.Dock="Bottom" Visibility="Collapsed"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + <ProgressBar x:Name="xaml_DistillProgress" Grid.Row="0" Grid.Column="0" Margin="3" Minimum="0" + Maximum="100" Height="20" HorizontalAlignment="Stretch"/> + <TextBlock Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Margin="5, 0, 5, 0"><Bold>Distilling</Bold></TextBlock> + <Button Grid.Row="0" Grid.Column="2" Width="50" Height="20" Name="xaml_CancelDistill" Click="CancelDistillClick" Background="Transparent" BorderBrush="Transparent" Margin="5,0,5,0"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Height="Auto" RadiusX="5" RadiusY="5"> + <Rectangle.Fill > + <SolidColorBrush Color="LightSlateGray"></SolidColorBrush> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + <TextBlock><Bold>Cancel</Bold></TextBlock> + </Button> + </Grid> + + <!-- Thumb viewer/selector --> + <Grid x:Name="xaml_ThumbGrid" Width="100" Background="DarkGray" DockPanel.Dock="Left" Visibility="Collapsed"> + <ListView x:Name="xaml_ThumbList" HorizontalAlignment="Stretch" + ItemTemplate="{StaticResource PageTemplate}" + ScrollViewer.CanContentScroll="False" + Background="DarkGray" ScrollViewer.PanningMode="Both" + PreviewMouseLeftButtonUp="ThumbSelected"> + </ListView> + </Grid> + <!-- Contents viewer/selector --> + <Grid x:Name="xaml_ContentGrid" Width="250" Background="DarkGray" DockPanel.Dock="Left" Visibility="Collapsed"> + <ListView x:Name="xaml_ContentList" HorizontalAlignment="Stretch" + ScrollViewer.CanContentScroll="False" PreviewMouseLeftButtonUp="ContentSelected" + Background="DarkGray" ScrollViewer.PanningMode="Both"> + <ListView.ItemTemplate> + <DataTemplate> + <StackPanel Margin="5,5,0,0" HorizontalAlignment="Left"> + <TextBlock TextWrapping="Wrap" Text="{Binding StringMargin}" FontFamily="Segoe UI" FontSize="11" /> + </StackPanel> + </DataTemplate> + </ListView.ItemTemplate> + </ListView> + </Grid> + <!-- Pages are last child fill. This goes in the center of our dock panel --> + <Grid x:Name="xaml_PageGrid" HorizontalAlignment="Stretch" Background="DarkGray" > + <ListView x:Name="xaml_PageList" HorizontalAlignment="Stretch" + ItemTemplate="{StaticResource PageTemplate}" + ScrollViewer.CanContentScroll="False" + Background="DarkGray" ScrollViewer.PanningMode="Both" + ScrollViewer.ScrollChanged="ListViewScrollChanged"> + <ListView.ItemContainerStyle> + <Style TargetType="ListViewItem"> + <Setter Property="HorizontalContentAlignment" Value="Stretch"/> + </Style> + </ListView.ItemContainerStyle> + </ListView> + </Grid> - </Grid> + </DockPanel> </Window> diff --git a/platform/winrt/gsview/MainWindow.xaml.cs b/platform/winrt/gsview/MainWindow.xaml.cs index 1e23d84e..71726468 100644 --- a/platform/winrt/gsview/MainWindow.xaml.cs +++ b/platform/winrt/gsview/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -13,9 +14,11 @@ using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Forms; -using mupdfwinrt; -using System.Threading.Tasks; -using System.Runtime.InteropServices.WindowsRuntime; +using System.ComponentModel; +using System.IO; +using System.Windows.Xps.Packaging; +using System.Printing; +using System.Windows.Markup; enum AppBar_t { @@ -37,7 +40,7 @@ enum RenderingStatus_t REN_PAGE /* Used to ignore value when source based setting */ }; -enum status_t +public enum status_t { S_ISOK, E_FAILURE, @@ -67,7 +70,7 @@ public struct spatial_info_t { public Point size; public double scale_factor; -} ; +}; /* C# has no defines.... */ static class Constants @@ -85,7 +88,7 @@ static class Constants public const int KEY_MINUS = 0xbd; public const int ZOOM_IN = 0; public const int ZOOM_OUT = 1; - public const double screenScale = 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; @@ -97,8 +100,18 @@ namespace gsview /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> + /// + + public struct thumb_t + { + public int page_num; + public Byte[] bitmap; + public Point size; + } + public partial class MainWindow : Window { + mudocument mu_doc; public Pages m_docPages; List<DocPage> m_thumbnails; List<List<RectList>> m_page_link_list; @@ -108,37 +121,125 @@ namespace gsview List<RectList> m_text_list; private int m_rectlist_page; private List<ContentEntry> m_content_list; - mudocument mu_doc; private bool m_file_open; private int m_currpage; private int m_searchpage; private int m_num_pages; - private int m_slider_min; - private int m_slider_max; private bool m_init_done; - private bool m_flip_from_searchlink; private bool m_links_on; private int m_search_rect_count; private bool m_page_update; - WriteableBitmap m_BlankBmp; String m_textcolor; String m_linkcolor; RenderingStatus_t m_ren_status; - private bool m_insearch; /* Used for UI display */ - private bool m_search_active; /* Used to avoid multiple UI clicks */ - private bool m_sliderchange; - private double m_Progress; - int m_width; - int m_height; + private bool m_insearch; + private bool m_search_active; private bool m_handlingzoom; - private double m_panX; - private double m_panY; private bool m_have_thumbs; + private bool m_have_contents; + double m_doczoom; + ghostsharp m_ghostscript; + String m_currfile; + private gsprint m_ghostprint = null; + bool m_isXPS; + gsOutput m_gsoutput; + Convert m_convertwin; public MainWindow() { InitializeComponent(); + this.Closing += new System.ComponentModel.CancelEventHandler(Window_Closing); + m_file_open = false; + status_t result = CleanUp(); + + /* Allocations */ + try + { + m_docPages = new Pages(); + m_thumbnails = new List<DocPage>(); + m_page_link_list = new List<List<RectList>>(); + m_text_list = new List<RectList>(); + m_linkset = new List<bool>(); + m_ghostscript = new ghostsharp(); + m_ghostscript.gsUpdateMain += new ghostsharp.gsCallBackMain(gsProgress); + m_gsoutput = new gsOutput(); + m_gsoutput.Activate(); + m_ghostscript.gsIOUpdateMain += new ghostsharp.gsIOCallBackMain(gsIO); + m_convertwin = null; + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed at initialization\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + + void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) + { + m_gsoutput.RealWindowClosing(); + } + + private status_t CleanUp() + { + m_init_done = false; + + /* Clear out everything */ + if (m_docPages != null && m_docPages.Count > 0) + m_docPages.Clear(); + if (m_thumbnails != null && m_thumbnails.Count > 0) + m_thumbnails.Clear(); + if (m_page_link_list != null && m_page_link_list.Count > 0) + m_page_link_list.Clear(); + if (m_text_list != null && m_text_list.Count > 0) + m_text_list.Clear(); + if (m_linkset != null && m_linkset.Count > 0) + m_linkset.Clear(); + + 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); + } + status_t result = mu_doc.Initialize(); + + 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_insearch = false; + m_search_active = false; + m_num_pages = -1; + m_search_rect_count = 0; + m_links_on = false; + m_rectlist_page = -1; + m_doczoom = 1.0; + m_isXPS = false; + return result; + } + + 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 CloseDoc() @@ -148,10 +249,155 @@ namespace gsview } + /* 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) + { + 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; + + 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); + } + } + + void SetThumbInit(int page_num, Byte[] bitmap, Point ras_size, double zoom_in) + { + /* Two jobs. Store the thumb and possibly update the full page */ + DocPage doc_page = m_thumbnails[page_num]; + + doc_page.Width = (int)ras_size.X; + doc_page.Height = (int)ras_size.Y; + 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; + + /* And the main page */ + var doc = m_docPages[page_num]; + if (doc.Content == Page_Content_t.THUMBNAIL || doc.Content == Page_Content_t.FULL_RESOLUTION) + return; + else + { + doc_page = this.m_docPages[page_num]; + 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; + } + } + + private void ThumbsWork(object sender, DoWorkEventArgs e) + { + Point ras_size; + status_t code; + double scale_factor; + spatial_info_t spatial_info = InitSpatial(1); + BackgroundWorker worker = sender as BackgroundWorker; + + spatial_info.scale_factor = Constants.SCALE_THUMB; + Byte[] bitmap; + + for (int k = 0; k < m_num_pages; k++) + { + if (ComputePageSize(spatial_info, k, out ras_size, out scale_factor) == 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, false); + } + 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); + } + } + } + } + + 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; + } + + 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); + m_docPages[thumb.page_num].PageRefresh(); + m_thumbnails[thumb.page_num].PageRefresh(); + } + + 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 + { + BackgroundWorker worker = new BackgroundWorker(); + worker.WorkerReportsProgress = true; + worker.WorkerSupportsCancellation = true; + worker.DoWork += new DoWorkEventHandler(ThumbsWork); + worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ThumbsCompleted); + worker.ProgressChanged += new ProgressChangedEventHandler(ThumbsProgressChanged); + xaml_ProgressGrid.Visibility = System.Windows.Visibility.Visible; + worker.RunWorkerAsync(); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during thumb rendering\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + + private spatial_info_t InitSpatial(double scale) + { + spatial_info_t value = new spatial_info_t(); + + value.size.Y = this.ActualHeight; + value.size.X = this.ActualWidth; + value.scale_factor = scale; + return value; + } + private void OpenFile(object sender, RoutedEventArgs e) { OpenFileDialog dlg = new OpenFileDialog(); - dlg.Filter = "Xps Documents (*.xps)|*.xps"; + dlg.Filter = "Document Files(*.ps;*.eps;*.pdf;*.xps;*.cbz)|*.ps;*.eps;*.pdf;*.xps;*.cbz|All files (*.*)|*.*"; dlg.FilterIndex = 1; if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) { @@ -159,38 +405,502 @@ namespace gsview { CloseDoc(); } - try + /* 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(dlg.FileName); + if (extension.ToUpper() == ".PS" || extension.ToUpper() == ".EPS") + { + xaml_DistillProgress.Value = 0; + if (m_ghostscript.DistillPS(dlg.FileName) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS currently busy"); + return; + } + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; + return; + } + + /* Set if this is already xps for printing */ + if (extension.ToUpper() == ".XPS") + m_isXPS = true; + + StartViewer(dlg.FileName); + + } + } + + private void StartViewer(String File) + { + m_currfile = File; + status_t code = mu_doc.OpenFile(m_currfile); + if (code == status_t.S_ISOK) + { + InitialRender(); + RenderThumbs(); + m_file_open = true; + } + else + { + m_currfile = null; + ShowMessage(NotifyType_t.MESS_ERROR, "Failed to open file!"); + } + } + + private status_t ComputePageSize(spatial_info_t spatial_info, int page_num, + out Point render_size, out double scale_factor) + { + Point screenSize = new Point(); + Point renpageSize = new Point(); + + status_t code = (status_t)mu_doc.GetPageSize(page_num, out render_size); + if (code != status_t.S_ISOK) + { + scale_factor = 1.0; + return code; + } + + screenSize = spatial_info.size; + screenSize.Y *= Constants.SCREEN_SCALE; + screenSize.X *= Constants.SCREEN_SCALE; + + double hscale = screenSize.X / render_size.X; + double vscale = screenSize.Y / render_size.Y; + double scale = Math.Min(hscale, vscale); + renpageSize.X = (render_size.X * scale * spatial_info.scale_factor); + renpageSize.Y = (render_size.Y * scale * spatial_info.scale_factor); + + scale_factor = (scale * spatial_info.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.DUMMY; + doc_page.TextBox = null; + doc_page.LinkBox = null; + return doc_page; + } + + async private void InitialRender() + { + m_num_pages = mu_doc.GetPageCount(); + m_currpage = 0; + + for (int k = 0; k < m_num_pages; k++) + { + m_docPages.Add(InitDocPage()); + m_thumbnails.Add(InitDocPage()); + /* Create empty lists for our links and specify that they have + not been computed for these pages */ + List<RectList> temp_link = new List<RectList>(); + m_page_link_list.Add(temp_link); + m_linkset.Add(false); + } + + /* Do the first few full res pages */ + spatial_info_t spatial_info = InitSpatial(1); + for (int k = 0; k < Constants.LOOK_AHEAD + 2; k++) + { + if (m_num_pages > k) { - OpenDocument(dlg.FileName); + Point ras_size; + double scale_factor; + + if (ComputePageSize(spatial_info, k, out ras_size, out scale_factor) == status_t.S_ISOK) + { + try + { + Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4]; + + Task<int> ren_task = + new Task<int>(() => mu_doc.RenderPage(k, bitmap, (int)ras_size.X, (int)ras_size.Y, scale_factor, false, true)); + ren_task.Start(); + await ren_task.ContinueWith((antecedent) => + { + status_t code = (status_t)ren_task.Result; + if (code == status_t.S_ISOK) + UpdatePage(k, bitmap, ras_size, Page_Content_t.FULL_RESOLUTION, 1.0); + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed page " + k + "\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } } - catch (UnauthorizedAccessException) + } + m_init_done = true; + xaml_PageList.ItemsSource = m_docPages; + } + + private void OnBackPageClick(object sender, RoutedEventArgs e) + { + if (m_currpage == 0) return; + + m_currpage = m_currpage - 1; + xaml_PageList.ScrollIntoView(m_docPages[m_currpage]); + } + + private void OnForwardPageClick(object sender, RoutedEventArgs e) + { + if (m_currpage == m_num_pages - 1) return; + + m_currpage = m_currpage + 1; + xaml_PageList.ScrollIntoView(m_docPages[m_currpage]); + } + + private void CancelLoadClick(object sender, RoutedEventArgs e) + { + /* Cancel during thumbnail loading. Deactivate the button + * and cancel the thumbnail rendering */ + } + + private void ToggleThumbs(object sender, RoutedEventArgs e) + { + if (m_have_thumbs) + { + if (xaml_ThumbGrid.Visibility == System.Windows.Visibility.Collapsed) { - System.Windows.MessageBox.Show( - String.Format("Unable to access {0}", dlg.FileName)); + 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) + { + xaml_PageList.ScrollIntoView(m_docPages[item.PageNum]); + } + } + + private void ContentSelected(object sender, MouseButtonEventArgs e) + { + var item = ((FrameworkElement)e.OriginalSource).DataContext as ContentItem; + if (item != null && item.Page < m_num_pages) + { + xaml_PageList.ScrollIntoView(m_docPages[item.Page]); + } + } + + private void ListViewScrollChanged(object sender, ScrollChangedEventArgs e) + { + var lv = (System.Windows.Controls.ListView) sender; + foreach (var lvi in lv.Items) + { + var container = lv.ItemContainerGenerator.ContainerFromItem(lvi) as ListBoxItem; + if (container != null && Visible(container, lv)) + { + var found = container.Content; + if (found != null) + { + var Item = (DocPage)found; + RenderRange(Item.PageNum); + } return; } } } - private async void OpenDocument(String filename) + /* Render +/- the look ahead from where we are if blank page is present */ + async private void RenderRange(int curr_page) + { + spatial_info_t spatial_info = InitSpatial(m_doczoom); + int range = Constants.LOOK_AHEAD; + + range = 0; // debug + for (int k = curr_page - range; k <= curr_page + range; 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) + { + Point ras_size; + double scale_factor; + + if (ComputePageSize(spatial_info, k, out ras_size, out scale_factor) == status_t.S_ISOK) + { + try + { + Byte[] bitmap = new byte[(int)ras_size.X * (int)ras_size.Y * 4]; + + Task<int> ren_task = + new Task<int>(() => mu_doc.RenderPage(k, bitmap, (int)ras_size.X, (int)ras_size.Y, scale_factor, false, true)); + ren_task.Start(); + await ren_task.ContinueWith((antecedent) => + { + status_t code = (status_t)ren_task.Result; + if (code == status_t.S_ISOK) + { + UpdatePage(k, bitmap, ras_size, Page_Content_t.FULL_RESOLUTION, 1.0); + m_docPages[k].PageRefresh(); + } + }, TaskScheduler.FromCurrentSynchronizationContext()); + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed page " + k + "\n"); + ShowMessage(NotifyType_t.MESS_ERROR, "Out of memory: " + e.Message); + } + } + } + } + } + } + + private bool Visible(FrameworkElement elem, FrameworkElement cont) + { + if (!elem.IsVisible) + return false; + Rect rect = new Rect(0.0, 0.0, cont.ActualWidth, cont.ActualHeight); + Rect bounds = elem.TransformToAncestor(cont).TransformBounds(new Rect(0.0, 0.0, elem.ActualWidth, elem.ActualHeight)); + Rect bounds2 = new Rect(new Point(bounds.TopLeft.X, bounds.TopLeft.Y), new Point(bounds.BottomRight.X, bounds.BottomRight.Y - 5)); + return rect.Contains(bounds2.TopLeft) || rect.Contains(bounds2.BottomRight); + } + + private void ReleasePages(int old_page, int new_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 = old_page - Constants.LOOK_AHEAD; k <= old_page + Constants.LOOK_AHEAD; k++) + { + if (k < new_page - Constants.LOOK_AHEAD || k > new_page + Constants.LOOK_AHEAD) + { + if (k >= 0 && k < m_num_pages) + { + SetThumb(k); + } + } + } + } + + /* Return this page from a full res image to the thumb image or only set + to thumb if it has not already been set */ + private void SetThumb(int page_num) + { + /* See what is there now */ + var doc = m_docPages[page_num]; + if (doc.Content == Page_Content_t.THUMBNAIL && doc.Zoom == m_doczoom) return; + + if (m_thumbnails.Count > page_num) + { + m_page_update = true; + var thumb_page = m_thumbnails[page_num]; + thumb_page.Height = (int)(thumb_page.NativeHeight * m_doczoom); + thumb_page.Width = (int)(thumb_page.NativeWidth * m_doczoom); + thumb_page.Zoom = 1.0; + m_docPages[page_num] = thumb_page; + m_page_update = false; + } + } + + private void LinksToggle(object sender, RoutedEventArgs e) { - string target = "."; - char[] anyOf = target.ToCharArray(); - var index = filename.LastIndexOfAny(anyOf); - string extension = filename.Substring(index + 1); + } - int result = mu_doc.OpenFileName(filename, extension); + private void Search(object sender, RoutedEventArgs e) + { - //int result = await mu_doc.OpenFileAsync(filename, extension); - /* Check if we need password */ - //if (mu_doc.RequiresPassword()) - //{ - //SetView(view_t.VIEW_PASSWORD); - // return; - //} - //else - // InitialRender(); + } + + private void ZoomOut(object sender, RoutedEventArgs e) + { + + } + + private void ZoomIn(object sender, RoutedEventArgs e) + { + + } + + private void CancelSearchClick(object sender, RoutedEventArgs e) + { + + } + + private void gsIO(object gsObject, String mess, int len) + { + m_gsoutput.Update(mess, len); + } + + private void gsProgress(object gsObject, gsEventArgs asyncInformation) + { + if (asyncInformation.Completed) + { + xaml_DistillProgress.Value = 100; + xaml_DistillProgress.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: + + break; + } + return; + } + GSResult(asyncInformation.Params); + } + else + { + xaml_PrintProgress.Value = asyncInformation.Progress; + } + } + + /* GS Result*/ + public void GSResult(gsParams_t result) + { + switch (result.task) + { + case GS_Task_t.CREATE_XPS: + PrintXPS(result.outputfile); + break; + + case GS_Task_t.PS_DISTILL: + StartViewer(result.outputfile); + break; + + case GS_Task_t.SAVE_RESULT: + + break; + } + } + + + /* 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 file is already xps then gs need not do this */ + if (!m_isXPS) + { + xaml_DistillProgress.Value = 0; + if (m_ghostscript.CreateXPS(m_currfile) == gsStatus.GS_BUSY) + { + ShowMessage(NotifyType_t.MESS_STATUS, "GS currently busy"); + return; + } + else + { + xaml_DistillGrid.Visibility = System.Windows.Visibility.Visible; + } + + } + PrintXPS(m_currfile); + } + + private void PrintXPS(String file) + { + gsprint ghostprint = new gsprint(); + System.Windows.Controls.PrintDialog pDialog = ghostprint.GetPrintDialog(); + + if (pDialog == null) + return; + + XpsDocument xpsDocument = new XpsDocument(file, FileAccess.Read); + FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence(); + + PrintQueue printQueue = pDialog.PrintQueue; + + m_ghostprint = ghostprint; + xaml_PrintGrid.Visibility = System.Windows.Visibility.Visible; + m_ghostprint.PrintUpdate += new gsprint.AsyncPrintCallBack(PrintProgress); + + xaml_PrintProgress.Value = 0; + + ghostprint.Print(printQueue, fixedDocSeq); + } + + private void PrintProgress(object printHelper, gsPrintEventArgs asyncInformation) + { + if (asyncInformation.Completed) + { + xaml_PrintProgress.Value = 100; + xaml_PrintGrid.Visibility = System.Windows.Visibility.Collapsed; + } + else + { + xaml_PrintProgress.Value = 100 * (double) asyncInformation.Page / (double) m_num_pages; + } + } + + private void CancelDistillClick(object sender, RoutedEventArgs e) + { + + } + + 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_convertwin == null) + { + m_convertwin = new Convert(m_num_pages); + m_convertwin.Activate(); + m_convertwin.Show(); + } } } } + diff --git a/platform/winrt/gsview/Properties/AssemblyInfo.cs b/platform/winrt/gsview/Properties/AssemblyInfo.cs index 4cb76a71..77e3ac52 100644 --- a/platform/winrt/gsview/Properties/AssemblyInfo.cs +++ b/platform/winrt/gsview/Properties/AssemblyInfo.cs @@ -12,7 +12,7 @@ using System.Windows; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("gsview")] -[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/platform/winrt/gsview/RectList.cs b/platform/winrt/gsview/RectList.cs new file mode 100644 index 00000000..3c761876 --- /dev/null +++ b/platform/winrt/gsview/RectList.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace gsview +{ + public class RectList + { + public String Index + { + get; + set; + } + + public String Color + { + get; + set; + } + + public int Height + { + get; + set; + } + + public int Width + { + get; + set; + } + + public int X + { + get; + set; + } + + public int Y + { + get; + set; + } + + public int Type + { + get; + set; + } + + public int PageNum + { + get; + set; + } + + public Uri Urilink + { + get; + set; + } + } +} diff --git a/platform/winrt/gsview/Resources/Left.ico b/platform/winrt/gsview/Resources/Left.ico Binary files differnew file mode 100644 index 00000000..b2507e31 --- /dev/null +++ b/platform/winrt/gsview/Resources/Left.ico diff --git a/platform/winrt/gsview/Resources/Right.ico b/platform/winrt/gsview/Resources/Right.ico Binary files differnew file mode 100644 index 00000000..c2f9238f --- /dev/null +++ b/platform/winrt/gsview/Resources/Right.ico diff --git a/platform/winrt/gsview/Resources/contents.ico b/platform/winrt/gsview/Resources/contents.ico Binary files differnew file mode 100644 index 00000000..97a12dd8 --- /dev/null +++ b/platform/winrt/gsview/Resources/contents.ico diff --git a/platform/winrt/gsview/Resources/gsview.ico b/platform/winrt/gsview/Resources/gsview.ico Binary files differnew file mode 100644 index 00000000..65b8b6b9 --- /dev/null +++ b/platform/winrt/gsview/Resources/gsview.ico diff --git a/platform/winrt/gsview/Resources/gsview.png b/platform/winrt/gsview/Resources/gsview.png Binary files differnew file mode 100644 index 00000000..bfcfb8db --- /dev/null +++ b/platform/winrt/gsview/Resources/gsview.png diff --git a/platform/winrt/gsview/Resources/hyperlink.png b/platform/winrt/gsview/Resources/hyperlink.png Binary files differnew file mode 100644 index 00000000..6ea0d798 --- /dev/null +++ b/platform/winrt/gsview/Resources/hyperlink.png diff --git a/platform/winrt/gsview/Resources/printer.ico b/platform/winrt/gsview/Resources/printer.ico Binary files differindex 34a15747..c03d9853 100644 --- a/platform/winrt/gsview/Resources/printer.ico +++ b/platform/winrt/gsview/Resources/printer.ico diff --git a/platform/winrt/gsview/Resources/search.ico b/platform/winrt/gsview/Resources/search.ico Binary files differnew file mode 100644 index 00000000..2841a637 --- /dev/null +++ b/platform/winrt/gsview/Resources/search.ico diff --git a/platform/winrt/gsview/Resources/search.png b/platform/winrt/gsview/Resources/search.png Binary files differnew file mode 100644 index 00000000..9bbb2255 --- /dev/null +++ b/platform/winrt/gsview/Resources/search.png diff --git a/platform/winrt/gsview/Resources/thumbnail.ico b/platform/winrt/gsview/Resources/thumbnail.ico Binary files differnew file mode 100644 index 00000000..71d38e97 --- /dev/null +++ b/platform/winrt/gsview/Resources/thumbnail.ico diff --git a/platform/winrt/gsview/Resources/zoom_in.ico b/platform/winrt/gsview/Resources/zoom_in.ico Binary files differnew file mode 100644 index 00000000..b0ca2ead --- /dev/null +++ b/platform/winrt/gsview/Resources/zoom_in.ico diff --git a/platform/winrt/gsview/Resources/zoom_out.ico b/platform/winrt/gsview/Resources/zoom_out.ico Binary files differnew file mode 100644 index 00000000..a31d6c8b --- /dev/null +++ b/platform/winrt/gsview/Resources/zoom_out.ico diff --git a/platform/winrt/gsview/ghostsharp.cs b/platform/winrt/gsview/ghostsharp.cs new file mode 100644 index 00000000..50c08b57 --- /dev/null +++ b/platform/winrt/gsview/ghostsharp.cs @@ -0,0 +1,453 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks;using System.Runtime.InteropServices; +using System.IO; +using System.Security; +using System.ComponentModel; + +namespace gsview +{ + public enum gsDevice_t + { + bmp16, + bmp16m, + bmp256, + bmp32b, + bmpgray, + bmpmono, + epswrite, + jpeg, + jpegcmyk, + jpeggray, + pamcmyk32, + pamcmyk4, + pbm, + pgm, + png16, + png16m, + png256, + pngalpha, + pnggray, + pngmono, + pdfwrite, + ps2write, + psdcmyk, + psdrgb, + pxlcolor, + pxlmono, + tiff12nc, + tiff24nc, + tiff32nc, + tiff64nc, + tiffcrle, + tiffg3, + tiffg32d, + tiffg4, + tiffgray, + tifflzw, + tiffpack, + tiffsep, + txtwrite, + xpswrite + }; + + public enum GS_Task_t + { + PS_DISTILL, + CREATE_XPS, + SAVE_RESULT + } + + public enum GS_Result_t + { + gsOK, + gsFAILED + } + + /* Parameters */ + public struct gsParams_t + { + public int resolution; + public gsDevice_t device; + public String outputfile; + public String inputfile; + public GS_Task_t task; + public GS_Result_t result; + }; + + public class gsEventArgs : EventArgs + { + private bool m_completed; + private int m_progress; + private gsParams_t m_param; + + public bool Completed + { + get { return m_completed; } + } + + public gsParams_t Params + { + get { return m_param; } + } + + public int Progress + { + get { return m_progress; } + } + + public gsEventArgs(bool completed, int progress, gsParams_t param) + { + m_completed = completed; + m_progress = progress; + m_param = param; + } + } + + /* from gs */ + struct gsapi_revision_t + { + IntPtr product; + IntPtr copyright; + long revision; + long revisiondate; + } + + public enum gsEncoding { + GS_ARG_ENCODING_LOCAL = 0, + GS_ARG_ENCODING_UTF8 = 1, + GS_ARG_ENCODING_UTF16LE = 2 + }; + + public enum gsStatus + { + GS_READY, + GS_BUSY, + GS_ERROR + }; + + [SuppressUnmanagedCodeSecurity] + class ghostsharp + { + /* Callback proto for stdio */ + public delegate int gsStdIOHandler(IntPtr caller_handle, IntPtr buffer, + int len); + + /* Ghostscript API */ + [DllImport("gsdll64.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + public static extern int gsapi_revision(IntPtr stuct, int size); + + [DllImport("gsdll64.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + public static extern int gsapi_new_instance(out IntPtr pinstance, + IntPtr caller_handle); + + [DllImport("gsdll64.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + public static extern void gsapi_delete_instance(IntPtr instance); + + [DllImport("gsdll64.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + public static extern int gsapi_init_with_args(IntPtr instance, int argc, + IntPtr argv); + + [DllImport("gsdll64.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + public static extern int gsapi_exit(IntPtr instance); + + [DllImport("gsdll64.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + public static extern int gsapi_set_arg_encoding(IntPtr instance, + int encoding); + + [DllImport("gsdll64.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + public static extern int gsapi_set_stdio(IntPtr instance, + gsStdIOHandler stdin, gsStdIOHandler stdout, gsStdIOHandler stderr); + + private int StdInCallback(IntPtr handle, IntPtr pointer, int count) + { + String output = Marshal.PtrToStringAnsi(pointer); + return count; + } + + private int StdOutCallback(IntPtr handle, IntPtr pointer, int count) + { + String output = Marshal.PtrToStringAnsi(pointer); + gsIOUpdateMain(this, output, count); + return count; + } + + private int StdErrCallback(IntPtr handle, IntPtr pointer, int count) + { + String output = Marshal.PtrToStringAnsi(pointer); + gsIOUpdateMain(this, output, count); + return count; + } + + IntPtr gsInstance; + BackgroundWorker m_worker; + /* Callbacks to Main */ + internal delegate void gsIOCallBackMain(object gsObject, String mess, int len); + internal event gsIOCallBackMain gsIOUpdateMain; + internal delegate void gsCallBackMain(object gsObject, gsEventArgs info); + internal event gsCallBackMain gsUpdateMain; + + public ghostsharp() + { + m_worker = null; + gsInstance = IntPtr.Zero; + } + + /* A standard command line approach to using gs API */ + private void gsWork1(object sender, DoWorkEventArgs e) + { + gsParams_t Params = (gsParams_t) e.Argument; + String out_file = Params.outputfile; + String in_file = Params.inputfile; + int num_params = 9; + var argParam = new GCHandle[num_params]; + var argPtrs = new IntPtr[num_params]; + String[] strParams = new String[num_params]; + List<byte[]> CharacterArray = new List<byte[]>(num_params); + int e_Quit = -101; + GCHandle argPtrsStable; + + /* New instance */ + int code = gsapi_new_instance(out gsInstance, IntPtr.Zero); + if (code < 0) + { + Params.result = GS_Result_t.gsFAILED; + e.Result = Params; + return; + } + + var RaiseStdInCallback = new gsStdIOHandler(StdInCallback); + var RaiseStdOutCallback = new gsStdIOHandler(StdOutCallback); + var RaiseStdErrCallback = new gsStdIOHandler(StdErrCallback); + + var stdInPtr = Marshal.GetFunctionPointerForDelegate(RaiseStdInCallback); + var stdOutPtr = Marshal.GetFunctionPointerForDelegate(RaiseStdOutCallback); + var stdErrPtr = Marshal.GetFunctionPointerForDelegate(RaiseStdErrCallback); + + // Setup stdio callback functions + //code = gsapi_set_stdio(gsInstance, stdInPtr, stdOutPtr, stdErrPtr); + code = gsapi_set_stdio(gsInstance, RaiseStdInCallback, RaiseStdOutCallback, RaiseStdErrCallback); + + code = gsapi_set_arg_encoding(gsInstance, (int) gsEncoding.GS_ARG_ENCODING_UTF8); + if (code == 0) + { + strParams[0] = "gs"; /* This does not matter */ + strParams[1] = "-dNOPAUSE"; + strParams[2] = "-dBATCH"; + strParams[3] = "-dSAFER"; + strParams[4] = "-sDEVICE=" + Enum.GetName(typeof(gsDevice_t), Params.device); + strParams[5] = "-r" + Params.resolution; + /* Create temp file if file not specified */ + if (out_file == null) + { + out_file = Path.GetTempFileName(); + Params.outputfile = out_file; + } + strParams[6] = "-o" + out_file; + strParams[7] = "-f"; + strParams[8] = in_file; + + /* Now convert our Strings to char* and get pinned handles to these. + * This keeps the c# GC from moving stuff around on us */ + for (int k = 0; k < num_params; k++) + { + CharacterArray.Add(System.Text.Encoding.UTF8.GetBytes(strParams[k].ToCharArray())); + argParam[k] = GCHandle.Alloc(CharacterArray[k], GCHandleType.Pinned); + argPtrs[k] = argParam[k].AddrOfPinnedObject(); + } + /* Also stick the array of pointers into memory that will not be GCd */ + argPtrsStable = GCHandle.Alloc(argPtrs, GCHandleType.Pinned); + + code = gsapi_init_with_args(gsInstance, num_params, argPtrsStable.AddrOfPinnedObject()); + + /* All the pinned items need to be freed so the GC can do its job */ + for (int k = 0; k < num_params; k++) + { + argParam[k].Free(); + } + argPtrsStable.Free(); + } + + int code1 = gsapi_exit(gsInstance); + if ((code == 0) || (code == e_Quit)) + code = code1; + + RaiseStdInCallback = null; + RaiseStdOutCallback = null; + RaiseStdErrCallback = null; + + gsapi_delete_instance(gsInstance); + if ((code == 0) || (code == e_Quit)) + { + Params.result = GS_Result_t.gsOK; + e.Result = Params; + return; + } + + Params.result = GS_Result_t.gsFAILED; + e.Result = Params; + return; + } + + /* Feeding gs piecemeal so that we can have some progress callback */ + private void gsWork2(object sender, DoWorkEventArgs e) + { + gsParams_t Params = (gsParams_t)e.Argument; + String out_file = Params.outputfile; + String in_file = Params.inputfile; + int num_params = 10; + var argParam = new GCHandle[num_params]; + var argPtrs = new IntPtr[num_params]; + String[] strParams = new String[num_params]; + List<byte[]> CharacterArray = new List<byte[]>(num_params); + int e_Quit = -101; + GCHandle argPtrsStable; + + /* New instance */ + int code = gsapi_new_instance(out gsInstance, IntPtr.Zero); + if (code < 0) + { + Params.result = GS_Result_t.gsFAILED; + e.Result = Params; + return; + } + + code = gsapi_set_arg_encoding(gsInstance, (int)gsEncoding.GS_ARG_ENCODING_UTF8); + if (code == 0) + { + strParams[0] = "gs"; /* This does not matter */ + strParams[1] = "-dNOPAUSE"; + strParams[2] = "-dBATCH"; + strParams[3] = "-dSAFER"; + strParams[4] = "-sDEVICE=" + Enum.GetName(typeof(gsDevice_t), Params.device); + strParams[5] = "-r" + Params.resolution; + strParams[6] = "-sstdout=%sstderr"; /* Need to get setup to capture stdout and stderr */ + /* Create temp file if file not specified */ + if (out_file == null) + { + out_file = Path.GetTempFileName(); + Params.outputfile = out_file; + } + strParams[7] = "-sOutputFile=" + out_file; + strParams[8] = "-f"; + strParams[9] = in_file; + + /* Now convert our Strings to char* and get pinned handles to these. + * This keeps the c# GC from moving stuff around on us */ + for (int k = 0; k < num_params; k++) + { + CharacterArray.Add(System.Text.Encoding.UTF8.GetBytes(strParams[k].ToCharArray())); + argParam[k] = GCHandle.Alloc(CharacterArray[k], GCHandleType.Pinned); + argPtrs[k] = argParam[k].AddrOfPinnedObject(); + } + /* Also stick the array of pointers into memory that will not be GCd */ + argPtrsStable = GCHandle.Alloc(argPtrs, GCHandleType.Pinned); + + code = gsapi_init_with_args(gsInstance, num_params, argPtrsStable.AddrOfPinnedObject()); + + /* All the pinned items need to be freed so the GC can do its job */ + for (int k = 0; k < num_params; k++) + { + argParam[k].Free(); + } + argPtrsStable.Free(); + } + + int code1 = gsapi_exit(gsInstance); + if ((code == 0) || (code == e_Quit)) + code = code1; + + gsapi_delete_instance(gsInstance); + if ((code == 0) || (code == e_Quit)) + { + Params.result = GS_Result_t.gsOK; + e.Result = Params; + return; + } + + Params.result = GS_Result_t.gsFAILED; + e.Result = Params; + return; + } + + private void gsCompleted(object sender, RunWorkerCompletedEventArgs e) + { + /* Get the result and do the callback */ + gsParams_t Value = (gsParams_t)e.Result; + gsEventArgs info = new gsEventArgs(true, 100, Value); + gsUpdateMain(this, info); + } + + private void gsProgressChanged(object sender, ProgressChangedEventArgs e) + { + /* Get the result and do the callback */ + gsParams_t Value = new gsParams_t(); + gsEventArgs info = new gsEventArgs(false, e.ProgressPercentage, Value); + gsUpdateMain(this, info); + } + + public gsStatus DistillPS(String FileName) + { + gsParams_t Params = new gsParams_t(); ; + + Params.device = gsDevice_t.pdfwrite; + Params.outputfile = null; + Params.resolution = 300; + Params.inputfile = FileName; + Params.outputfile = null; + return RunGhostscript(Params); + } + + public gsStatus CreateXPS(String FileName) + { + gsParams_t Params = new gsParams_t(); ; + + Params.device = gsDevice_t.xpswrite; + Params.outputfile = null; + Params.resolution = 300; + Params.inputfile = FileName; + Params.outputfile = null; + return RunGhostscript(Params); + } + + private gsStatus RunGhostscript(gsParams_t Params) + { + /* 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 + { + if (m_worker != null) + { + m_worker.CancelAsync(); + return gsStatus.GS_BUSY; + } + m_worker = new BackgroundWorker(); + m_worker.WorkerReportsProgress = true; + m_worker.WorkerSupportsCancellation = true; + m_worker.DoWork += new DoWorkEventHandler(gsWork1); + m_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(gsCompleted); + m_worker.ProgressChanged += new ProgressChangedEventHandler(gsProgressChanged); + m_worker.RunWorkerAsync(Params); + return gsStatus.GS_READY; + } + catch (OutOfMemoryException e) + { + Console.WriteLine("Memory allocation failed during gs rendering\n"); + return gsStatus.GS_ERROR; + } + } + + } +} diff --git a/platform/winrt/gsview/gsIO.cs b/platform/winrt/gsview/gsIO.cs new file mode 100644 index 00000000..831f34f7 --- /dev/null +++ b/platform/winrt/gsview/gsIO.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel; + +namespace gsview +{ + class gsIO : INotifyPropertyChanged + { + public String gsIOString + { + get; + set; + } + + public event PropertyChangedEventHandler PropertyChanged; + + public void PageRefresh() + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs("gsIOString")); + } + } + + public gsIO() + { + this.gsIOString = ""; + } + } +} diff --git a/platform/winrt/gsview/gsOutput.xaml b/platform/winrt/gsview/gsOutput.xaml new file mode 100644 index 00000000..0be459a4 --- /dev/null +++ b/platform/winrt/gsview/gsOutput.xaml @@ -0,0 +1,35 @@ +<Window x:Class="gsview.gsOutput" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + Title="Ghostscript Messages" Height="500" Width="500"> + + <DockPanel LastChildFill="True"> + <Grid DockPanel.Dock="Bottom" Visibility="Visible" Background="WhiteSmoke"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*" /> + <ColumnDefinition Width="Auto" /> + </Grid.ColumnDefinitions> + <Button Grid.Row="0" Grid.Column="2" Width="50" Height="20" Click="HideWindow" Background="Transparent" BorderBrush="Transparent" Margin="5,0,15,0"> + <Button.Template> + <ControlTemplate TargetType="{x:Type Button}"> + <Grid> + <Rectangle Height="Auto" RadiusX="5" RadiusY="5"> + <Rectangle.Fill > + <SolidColorBrush Color="LightSlateGray"></SolidColorBrush> + </Rectangle.Fill> + </Rectangle> + <ContentPresenter Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"/> + </Grid> + </ControlTemplate> + </Button.Template> + <TextBlock><Bold>OK</Bold></TextBlock> + </Button> + </Grid> + + <!-- Pages are last child fill. This goes in the center of our dock panel --> + <Grid HorizontalAlignment="Stretch" Background="DarkGray"> + <TextBox x:Name="xaml_gsText" Margin="1, 1, 1, 1" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" Text="{Binding gsIOString}" IsReadOnly="True"/> + </Grid> + + </DockPanel> +</Window> diff --git a/platform/winrt/gsview/gsOutput.xaml.cs b/platform/winrt/gsview/gsOutput.xaml.cs new file mode 100644 index 00000000..90bb2d55 --- /dev/null +++ b/platform/winrt/gsview/gsOutput.xaml.cs @@ -0,0 +1,54 @@ +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; + +namespace gsview +{ + /// <summary> + /// Interaction logic for gsOutput.xaml + /// </summary> + public partial class gsOutput : Window + { + gsIO m_gsIO; + public gsOutput() + { + InitializeComponent(); + this.Closing += new System.ComponentModel.CancelEventHandler(FakeWindowClosing); + m_gsIO = new gsIO(); + xaml_gsText.DataContext = m_gsIO; + } + + void FakeWindowClosing(object sender, System.ComponentModel.CancelEventArgs e) + { + e.Cancel = true; + this.Hide(); + } + + private void HideWindow(object sender, RoutedEventArgs e) + { + this.Hide(); + } + + public void RealWindowClosing() + { + this.Closing -= new System.ComponentModel.CancelEventHandler(FakeWindowClosing); + this.Close(); + } + + public void Update(String newstring, int len) + { + m_gsIO.gsIOString += newstring.Substring(0, len); + m_gsIO.PageRefresh(); + } + } +} diff --git a/platform/winrt/gsview/gsprint.cs b/platform/winrt/gsview/gsprint.cs new file mode 100644 index 00000000..8fb7ad81 --- /dev/null +++ b/platform/winrt/gsview/gsprint.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Packaging; +using System.Printing; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Documents.Serialization; +using System.Windows.Media; +using System.Windows.Xps; +using System.Windows.Xps.Packaging; +using System.Windows.Xps.Serialization; + +namespace gsview +{ + /* Class for handling async print progress callback */ + public class gsPrintEventArgs : EventArgs + { + private String m_status; + private bool m_completed; + private int m_page; + + public String Status + { + get { return m_status; } + } + + public bool Completed + { + get { return m_completed; } + } + + public int Page + { + get { return m_page; } + } + + public gsPrintEventArgs(String status, bool completed, int page) + { + m_completed = completed; + m_status = status; + m_page = page; + } + } + + public class gsprint + { + private XpsDocumentWriter m_docWriter = null; + internal delegate void AsyncPrintCallBack(object printObject, gsPrintEventArgs info); + internal event AsyncPrintCallBack PrintUpdate; + + /* Show std. print dialog */ + public PrintDialog GetPrintDialog() + { + PrintDialog dlg = new PrintDialog(); + /* Current page and page ranges is going to require a little work */ + dlg.PageRangeSelection = PageRangeSelection.AllPages; + //dlg.UserPageRangeEnabled = true; + //dlg.CurrentPageEnabled = true; + dlg.SelectedPagesEnabled = false; + if (dlg.ShowDialog() == true) + return dlg; + return null; + } + + /* Main print entry point */ + public void Print(PrintQueue queu, FixedDocumentSequence fixdoc) + { + XpsDocumentWriter docwrite = GetDocWriter(queu); + + docwrite.WritingPrintTicketRequired += + new WritingPrintTicketRequiredEventHandler(PrintTicket); + PrintPages(docwrite, fixdoc); + } + + /* Send it */ + private void PrintPages(XpsDocumentWriter xpsdw, FixedDocumentSequence fixdoc) + { + m_docWriter = xpsdw; + xpsdw.WritingCompleted += + new WritingCompletedEventHandler(AsyncCompleted); + xpsdw.WritingProgressChanged += + new WritingProgressChangedEventHandler(AsyncProgress); + xpsdw.WriteAsync(fixdoc); + } + + public void CancelAsync() + { + /* ick. This does not work in windows 8. causes crash */ + /* https://connect.microsoft.com/VisualStudio/feedback/details/778145/xpsdocumentwriter-cancelasync-cause-crash-in-win8 */ + m_docWriter.CancelAsync(); + } + + /* Done */ + private void AsyncCompleted(object sender, WritingCompletedEventArgs e) + { + string status = null; + if (e.Cancelled) + status = "Print Canceled"; + else if (e.Error != null) + status = "Print Error"; + else + status = "Print Completed"; + + if (PrintUpdate != null) + { + gsPrintEventArgs info = new gsPrintEventArgs(status, true, 0); + PrintUpdate(this, info); + } + } + + /* Do this update with each fixed document (page) that is handled */ + private void AsyncProgress(object sender, WritingProgressChangedEventArgs e) + { + if (PrintUpdate != null) + { + String progress = "Page " + e.Number; + gsPrintEventArgs info = new gsPrintEventArgs(progress, false, e.Number); + PrintUpdate(this, info); + } + } + + /* Print ticket handling. You can customize for PrintTicketLevel at + FixedDocumentSequencePrintTicket, FixedDocumentPrintTicket, + or FixedPagePrintTicket. We may want to play around with this some */ + private void PrintTicket(Object sender, WritingPrintTicketRequiredEventArgs e) + { + if (e.CurrentPrintTicketLevel == + PrintTicketLevel.FixedDocumentSequencePrintTicket) + { + PrintTicket pts = new PrintTicket(); + pts.PageOrientation = PageOrientation.Portrait; + e.CurrentPrintTicket = pts; + } + } + + /* Create the document write */ + private XpsDocumentWriter GetDocWriter(PrintQueue pq) + { + XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(pq); + return xpsdw; + } + } +} diff --git a/platform/winrt/gsview/gsview.csproj b/platform/winrt/gsview/gsview.csproj index 961eab19..6856e925 100644 --- a/platform/winrt/gsview/gsview.csproj +++ b/platform/winrt/gsview/gsview.csproj @@ -13,6 +13,7 @@ <FileAlignment>512</FileAlignment> <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <WarningLevel>4</WarningLevel> + <IsWebBootstrapper>false</IsWebBootstrapper> <PublishUrl>publish\</PublishUrl> <Install>true</Install> <InstallFrom>Disk</InstallFrom> @@ -25,12 +26,11 @@ <MapFileExtensions>true</MapFileExtensions> <ApplicationRevision>0</ApplicationRevision> <ApplicationVersion>1.0.0.%2a</ApplicationVersion> - <IsWebBootstrapper>false</IsWebBootstrapper> <UseApplicationTrust>false</UseApplicationTrust> <BootstrapperEnabled>true</BootstrapperEnabled> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <PlatformTarget>AnyCPU</PlatformTarget> + <PlatformTarget>x64</PlatformTarget> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> @@ -38,9 +38,11 @@ <DefineConstants>TRACE;DEBUG</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + <Prefer32Bit>true</Prefer32Bit> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <PlatformTarget>AnyCPU</PlatformTarget> + <PlatformTarget>x64</PlatformTarget> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> @@ -48,19 +50,25 @@ <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> + <PropertyGroup> + <StartupObject /> + </PropertyGroup> + <PropertyGroup> + <ApplicationIcon>gsview.ico</ApplicationIcon> + </PropertyGroup> <ItemGroup> + <Reference Include="ReachFramework" /> <Reference Include="System" /> <Reference Include="System.Data" /> <Reference Include="System.Drawing" /> + <Reference Include="System.Printing" /> <Reference Include="System.Windows.Forms" /> <Reference Include="System.Xml" /> - <Reference Include="Microsoft.CSharp" /> - <Reference Include="System.Core" /> - <Reference Include="System.Xml.Linq" /> - <Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Xaml"> <RequiredTargetFramework>4.0</RequiredTargetFramework> </Reference> + <Reference Include="UIAutomationProvider" /> + <Reference Include="UIAutomationTypes" /> <Reference Include="WindowsBase" /> <Reference Include="PresentationCore" /> <Reference Include="PresentationFramework" /> @@ -71,8 +79,28 @@ <SubType>Designer</SubType> </ApplicationDefinition> <Compile Include="ContentEntry.cs" /> + <Compile Include="ContentItem.cs" /> + <Compile Include="Convert.xaml.cs"> + <DependentUpon>Convert.xaml</DependentUpon> + </Compile> <Compile Include="DocPage.cs" /> + <Compile Include="ghostsharp.cs" /> + <Compile Include="gsIO.cs" /> + <Compile Include="gsOutput.xaml.cs"> + <DependentUpon>gsOutput.xaml</DependentUpon> + </Compile> + <Compile Include="gsprint.cs" /> + <Compile Include="Links.cs" /> + <Compile Include="mudocument.cs" /> <Compile Include="RectList.cs" /> + <Page Include="Convert.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="gsOutput.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> <Page Include="MainWindow.xaml"> <Generator>MSBuild:Compile</Generator> <SubType>Designer</SubType> @@ -138,6 +166,31 @@ <Install>false</Install> </BootstrapperPackage> </ItemGroup> + <ItemGroup> + <Resource Include="Resources\Left.ico" /> + <Resource Include="Resources\Right.ico" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Resources\thumbnail.ico" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Resources\hyperlink.png" /> + <Resource Include="Resources\search.ico" /> + <Resource Include="Resources\zoom_in.ico" /> + <Resource Include="Resources\zoom_out.ico" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Resources\search.png" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Resources\contents.ico" /> + </ItemGroup> + <ItemGroup> + <Resource Include="Resources\gsview.ico" /> + </ItemGroup> + <ItemGroup> + <Resource Include="gsview.ico" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. diff --git a/platform/winrt/gsview/gsview.ico b/platform/winrt/gsview/gsview.ico Binary files differnew file mode 100644 index 00000000..65b8b6b9 --- /dev/null +++ b/platform/winrt/gsview/gsview.ico diff --git a/platform/winrt/gsview/mudocument.cs b/platform/winrt/gsview/mudocument.cs new file mode 100644 index 00000000..c9ccb4de --- /dev/null +++ b/platform/winrt/gsview/mudocument.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading; +using System.Runtime.InteropServices; +using System.Security; +using System.Windows; + +/* This file contains the interface between the muctx cpp class, which + implements the mupdf calls and the .net managed code */ + +namespace gsview +{ + + public struct content_s + { + public int page; + public IntPtr string_margin; + } + + [SuppressUnmanagedCodeSecurity] + class mudocument + { + IntPtr mu_object; + private System.Object m_lock = new System.Object(); + List<Links> links; + List<Links> textsearch; + public List<ContentItem> contents; + + /* The list of functions that we use to call into C interface of muctx. + * Calling into C++ code from managed code is complex. Since CLR + * compiling is needed and that does not support mutex. Hence the C + * interface */ + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern IntPtr mInitialize(); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern status_t mOpenDocument(IntPtr ctx, string filename); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern void mCleanUp(IntPtr ctx); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mGetPageCount(IntPtr ctx); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern bool mRequiresPassword(IntPtr ctx); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern bool mApplyPassword(IntPtr ctx, string password); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mRenderPage(IntPtr ctx, + int page_num, Byte[] bmp_data, int bmp_width, + int bmp_height, double scale, bool flipy); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mMeasurePage(IntPtr ctx, int page_num, + ref double width, ref double height); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mGetContents(IntPtr ctx); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern void mReleaseContents(); + + /* The managed code Marshal actually releases the allocated string from C */ + [DllImport("munet.dll", CharSet = CharSet.Ansi, + CallingConvention = CallingConvention.StdCall)] + [return: MarshalAs(UnmanagedType.LPStr)] + public static extern string mGetContentsItem(int k, ref int len, ref int page); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern IntPtr mCreateDisplayList(IntPtr ctx, int page_num, + ref int page_width, ref int page_height); + + [DllImport("munet.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern int mRenderPageMT(IntPtr ctx, IntPtr dlist, + int page_width, int page_height, Byte[] bmp_data, int bmp_width, + int bmp_height, double scale, bool flipy); + +/* + [DllImport("mugs.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern void GetLinks(IntPtr ctx); + + [DllImport("mugs.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern void GetTextSearch(IntPtr ctx); + + [DllImport("mugs.dll", CharSet = CharSet.Auto, + CallingConvention = CallingConvention.StdCall)] + public static extern void GetHTML(IntPtr ctx); + + ~muctx(void); + + unsigned int GetLinks(int page_num, sh_vector_link links_vec); + int GetTextSearch(int page_num, char* needle, sh_vector_text texts_vec); + std::string GetHTML(int page_num); +*/ + + public status_t Initialize() + { + mu_object = mInitialize(); + if (mu_object == null) + { + return status_t.E_FAILURE; + } + else + { + return status_t.S_ISOK; + } + } + + public void CleanUp() + { + if (mu_object != null) + mCleanUp(mu_object); + } + + public int GetPageCount() + { + return mGetPageCount(mu_object); + } + + public bool RequiresPassword() + { + return mRequiresPassword(mu_object); + } + + public bool ApplyPassword(String password) + { + return mApplyPassword(mu_object, password); + } + + public int RenderPage(int page_num, Byte[] bmp_data, int bmp_width, + int bmp_height, double scale, bool flipy, bool use_dlist) + { + int code; + + if (use_dlist) + { + IntPtr dlist; + int page_height = 0; + int page_width = 0; + + lock(m_lock) + { + dlist = mCreateDisplayList(mu_object, page_num, ref page_width, ref page_height); + } + /* Rendering of display list can occur with other threads so unlock */ + if (dlist == null) + { + return (int) status_t.E_FAILURE; + } + code = mRenderPageMT(mu_object, dlist, page_width, page_height, + bmp_data, bmp_width, bmp_height, + scale, flipy); + } + else + { + lock(m_lock) + { + code = mRenderPage(mu_object, page_num, bmp_data, bmp_width, + bmp_height, scale, flipy); + } + } + return code; + } + + public status_t OpenFile(string filename) + { + return mOpenDocument(mu_object, filename); + } + + public int GetPageSize(int page_num, out Point size_out) + { + int code; + double height = 0, width = 0; + + size_out = new Point(); + + lock(m_lock) + { + code = mMeasurePage(mu_object, page_num, ref width, ref height); + } + + size_out.X = width; + size_out.Y = height; + return code; + } + + public int ComputeContents() + { + int num_items; + int len = 0, page = 0; + + lock(m_lock) + { + num_items = mGetContents(mu_object); + } + + if (contents == null) + contents = new List<ContentItem>(); + + for (int k = 0; k < num_items; k++) + { + ContentItem item = new ContentItem(); + item.StringMargin = mGetContentsItem(k, ref len, ref page); + item.Page = page; + contents.Add(item); + } + return num_items; + } + + public void ReleaseContents() + { + mReleaseContents(); + } + } +} |