10

I am currently trying to print the contents of a content container (it only contains datagrids with information) and an image using PrintFixedDocument. It prints flawlessly on my machine (windows 10) with full image quality and on another pc which is windows 8, the quality is the same.

However when this is done on a Windows 7 pc the image quality becomes very poor and the final result is very blurred. This is a problem as the computer cannot be updated from windows 7 for various reasons, so im wondering if anyone else has experienced this and if so is there a workaround? Also could be an issue with my GetFixedDocument method, though I cannot work out why this would work on both win 10 and 8 but not 7.

NOTE THIS IS RUNNING FROM AN INSTALLED VERSION OF THE APPLICATION ON EACH PC

ALSO BEEN TRIED ON MULTIPLE PRINTERS ON ALL 3 OPERATING SYSTEMS

Any help would be appreciated

Xaml:

            <StackPanel Margin="-105,146,66,0" Height="900" VerticalAlignment="Top"  x:Name="PrintImageContextMenu">
                <Image Canvas.ZIndex="0" Source="{Binding Coupon.OverlayImagePath}"  Margin="0,-21,-76,108" Stretch="Fill"  />

                <ContentControl Content="{Binding}"  ContentTemplateSelector="{StaticResource DataViewerDataTemplateSelector}"  />

            </StackPanel>

C#: public partial class CouponViewerView { public CouponViewerView() { InitializeComponent(); }

    public void Print()
    {
        //Executes On Thread
        Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (EventHandler)delegate
        {
            UpdateLayout();

            var fixedDoc = PrintHelper.GetFixedDocument(StackPanelToPrint, new PrintDialog());

            PrintHelper.ShowPrintPreview(fixedDoc);


        }, null, null);



    }

    private void PrintCurrentForm(object sender, RoutedEventArgs e)
    {
        Print();
    }

C# Print helper code:

 public static void ShowPrintPreview(FixedDocument fixedDoc)
        {
            var wnd = new Window();
            var viewer = new DocumentViewer();
            viewer.Document = fixedDoc;
            wnd.Content = viewer;
            wnd.ShowDialog();
        }


  public static FixedDocument GetFixedDocument(FrameworkElement toPrint, PrintDialog printDialog)
        {
            var capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
            var pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
            var visibleSize = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
            var fixedDoc = new FixedDocument();
            //If the toPrint visual is not displayed on screen we neeed to measure and arrange it  
            toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize));
            //  
            var size = toPrint.DesiredSize;
            //Will assume for simplicity the control fits horizontally on the page  
            double yOffset = 0;
            while (yOffset < size.Height)
            {
                var vb = new VisualBrush(toPrint)
                {
                    Stretch = Stretch.None,
                    AlignmentX = AlignmentX.Left,
                    AlignmentY = AlignmentY.Top,
                    ViewboxUnits = BrushMappingMode.Absolute,
                    TileMode = TileMode.None,
                    Viewbox = new Rect(0, yOffset, visibleSize.Width, visibleSize.Height)
                };
                var pageContent = new PageContent();
                var page = new FixedPage();
                ((IAddChild)pageContent).AddChild(page);
                fixedDoc.Pages.Add(pageContent);
                page.Width = pageSize.Width;
                page.Height = pageSize.Height;
                var canvas = new Canvas();
                FixedPage.SetLeft(canvas, capabilities.PageImageableArea.OriginWidth);
                FixedPage.SetTop(canvas, capabilities.PageImageableArea.OriginHeight);
                canvas.Width = visibleSize.Width;
                canvas.Height = visibleSize.Height;
                canvas.Background = vb;
                page.Children.Add(canvas);
                yOffset += visibleSize.Height;
            }
            return fixedDoc;
        }
philmckendry
  • 555
  • 6
  • 21
  • Just for giggles even though I'm sure you've probably already checked. Have you checked the settings on the win7 machine to make sure it's not printing in Draft Mode or doing any manual resizing etc, as well as made sure any print drivers are up to date? – Chris W. Dec 15 '15 at 16:56
  • Yes have eliminated all the usual suspects. Printing to fine quality on all printers and all drivers are up to date. Its really strange as ive never seen anything like it. – philmckendry Dec 15 '15 at 17:23
  • Yea, I know they did some changes to the driver packages and stuff to try and coax manufacturers to quit loading on a bunch of OEM bloatware crap, but as far as I knew it should all get fed the same way regardless of OS version. That's an interesting one. – Chris W. Dec 15 '15 at 19:22
  • .NET 4.6 fixes a bug with the layout transform in WPF. Can you try installing .NET 4.6 on the Windows 7 machine? – Brannon Dec 16 '15 at 14:03
  • But it doesnt happen on my windows 8 and 10 laptops and all are running .Net 4.5.1? – philmckendry Dec 16 '15 at 14:58
  • Your GetFixedDocument method seems a little bit redundant to me. You actually dont need to create a VisualBrush and a canvas. Simply set your toPrint element as child of the FixedPage. – SnowballTwo Dec 16 '15 at 15:04
  • I will take that on board but that is unlikely to affect the quality of the print? – philmckendry Dec 16 '15 at 16:07
  • Maybe it does. Afaik the XPS is internally converted into GDI commands for printing. I also already had speed and quality issues with more complex drawing- and visualbrush printouts. – SnowballTwo Dec 18 '15 at 07:56

2 Answers2

0

anyone else has experienced this and if so is there a workaround?

That's the only directly answerable question, yes, many. Keep in mind that you often substantially rescale an image on a printer, they are devices with very high dots-per-inch resolution compared to a monitor. A machine that boots Win7 often runs at 96dpi, later ones tend to have better monitors so are often run at higher dpi settings. First thing to watch out for is the source image. If it has a pixel size that's adequate for that Win7 PC then it can get very blurry when it is blown-up to 600 dpi.

Probably the most unintuitive scaling behavior in WPF is what happens when the image alignment does not perfectly match a target pixel after scaling. A problem described well in this blog post. Be sure to also read this SO question, an almost perfect fit for your usage of VisualBrush and its blurriness problem. This problem was addressed in .NET 4.0 with the added UseLayoutRounding property. You are not using it, you definitely should. Don't blindly apply the BitmapScalingMode that the dup recommends, the type of image (line-art vs photo) matters a lot.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
0

I had a similar issue I ended up instead of directly printing to creating a PDF and having that open for the client and they could print it if they wanted just fine.

Windows 7 just seems broken with some of the WPF printing.

Cold Fire
  • 21
  • 4