0

I am just beginning to experiment with Ghostscript.Net. My goal is to adapt the GhostscriptViewer to my WPF MVVM Modular environment, but I am not able to display a page in a XAML Image control. I suspect that my problem lies either in my inadequate knowledge of Ghostscript.Net or in not understanding how to bind the image parameter to the image control.

In this app, I am using Prism with the UnityContainer. The PdfPageImage property in PdfViewModel is bound to the image control in the view XAML. The conversion, which takes place in the _viewer_displaypage method gives PdfPageImage an object of type System.Windows.Interop.InteropBitmap. I was thinking that the RaisePropertyChangedEvent method would cause the control to be updated with the ImageSource object.

            <Image x:Name="PdfDocumentImage" Grid.Column="1" Grid.Row="0" 
                   Source="{Binding PdfPageImage}"
                   Height="100"
                   Width="100">
            </Image>

    public class PdfViewModel : ViewModelBase, IPdfViewModel
{
    private readonly IBitmapToImageSourceConverter _imageSourceConverter;

    private readonly GhostscriptViewer _ghostscriptViewer;
    private readonly GhostscriptVersionInfo _gsVersion =
        GhostscriptVersionInfo.GetLastInstalledVersion(GhostscriptLicense.GPL | 
            GhostscriptLicense.AFPL, GhostscriptLicense.GPL);

    private ImageSource _pdfPageImage;
    public ImageSource PdfPageImage
    {
        get => _pdfPageImage;

        set
        {
            if (value == _pdfPageImage) return;
            _pdfPageImage = value;
            RaisePropertyChangedEvent(nameof(PdfPageImage));
        }
    }

    public PdfViewModel(IPdfView view,
        IEventAggregator eventAggregator,
        IBitmapToImageSourceConverter imageSourceConverter,
        GhostscriptViewer ghostscriptViewer)
        : base(view)
    {
        _ghostscriptViewer = ghostscriptViewer;
        _imageSourceConverter = imageSourceConverter;

        _ghostscriptViewer.DisplayPage += _viewer_DisplayPage;

        eventAggregator.GetEvent<PdfDocumentOpenedEvent>().Subscribe(OpenPdfDocument, ThreadOption.UIThread);
    }

    private void _viewer_DisplayPage(object sender, GhostscriptViewerViewEventArgs e)
    {
        PdfPageImage = _imageSourceConverter.ImageSourceForBitmap(e.Image);
    }

    private void OpenPdfDocument(string path)
    {
        _ghostscriptViewer.Open(path, _gsVersion, false);
    }
}

    public class BitmapToImageSourceConverter : IBitmapToImageSourceConverter
{
    [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool DeleteObject(IntPtr hObject);
    public ImageSource ImageSourceForBitmap(Bitmap bmp)
    {
        var handle = bmp.GetHbitmap();
        try
        {
            return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
        }
        finally { DeleteObject(handle); }
    }
}

1 Answers1

1

Okay. So I figured it out. My solution isn't perfect; while paging through a pdf document, the page orientation isn't correct, but other than that, it works.

The key was to use a memorystream in creating a BitmapImage:

        public static BitmapImage ConvertBitmapToImage(System.Drawing.Image image)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
            memoryStream.Position = 0;

            var bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            memoryStream.Seek(0, SeekOrigin.Begin);
            bitmapImage.StreamSource = memoryStream;
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();

            return bitmapImage;
        }
    }

Many other modifications were made to make the Ghostscrip.NET viewer work in my WPF MVVM app. If anybody is interested in more details, I will post more.