Question

This snippet is part of some code used to generate an XPS document. XPS document generation is no joke. I wish to avoid pasting any of that XPS code here if at all possible. Instead, this code focuses on the WPF portion of the problem.

The problem I am asking for you to help with is here. I have hard coded the dimensions to work for a test image:

double magicNumber_X = 3.5;//trial and error...3 too small 4 too big
fixedPage.Arrange(new Rect(new Point(magicNumber_X, 0), size));

Instead, how can I fix this code to calculate the coordinates?

Full Method:

    private PageContent AddContentFromImage()
    {
        var pageContent = new PageContent();
        var fixedPage = new FixedPage();            

        var bitmapImage = new BitmapImage(new Uri(hardCodedImageSampleFilePath, UriKind.RelativeOrAbsolute));

        var image = new Image();
        image.Source = bitmapImage;            
        fixedPage.Children.Add(image);

        ((IAddChild)pageContent).AddChild(fixedPage);

        double pageWidth = 96 * 8.5;//XPS documents are 96 units per inch
        double pageHeight = 96 * 11;

        fixedPage.Width = pageWidth;
        fixedPage.Height = pageHeight;

        var size = new Size(8.5 * 96, 11 * 96);

        fixedPage.Measure(size);
        double magicNumber_X = 3.5;//trial and error...3 too small 4 too big
        double magicNumber_Y = 0;
        fixedPage.Arrange(new Rect(new Point(magicNumber_X, magicNumber_Y), size));
        fixedPage.UpdateLayout();

        return pageContent;
    }

I'm a little surprised FixedPage.Measure(size) does not correct the issue by itself. I tried passing no params, e.g. fixedPage.Arrange(new Rect(), size)) still no go.

FWIW, this calculation worked fine when I was using PrintDocument.

private void pd_PrintPage(object sender, PrintPageEventArgs e)
    {
        Graphics g = e.Graphics;
        RectangleF marginBounds = e.MarginBounds;
        RectangleF printableArea = e.PageSettings.PrintableArea;

        int availableWidth = (int)Math.Floor(printDocument.OriginAtMargins ? marginBounds.Width : (e.PageSettings.Landscape ? printableArea.Height : printableArea.Width));
        int availableHeight = (int)Math.Floor(printDocument.OriginAtMargins ? marginBounds.Height : (e.PageSettings.Landscape ? printableArea.Width : printableArea.Height));

        Rectangle rectangle = new Rectangle(0,0, availableWidth -1, availableHeight - 1);        
        g.DrawImage(_image, rectangle);
Was it helpful?

Solution

I hooked into FixedPage.Loaded event because FixedPage.ActualHeight is required in order to perform the calculation and will not be set until the control has loaded. This also means that with this mechanism FixedPage has to be displayed to correctly perform an automated print.

    void fixedPage_Loaded(object sender, RoutedEventArgs e)
    {
        var fixedDocument = sender as FixedPage;
        CalculateSize(fixedDocument);
    }
    private void CalculateSize(FixedPage fixedPage)
    {
        PrintQueue printQueue = LocalPrintServer.GetDefaultPrintQueue();
        PrintCapabilities capabilities = printQueue.GetPrintCapabilities();

        //get scale of the print wrt to screen of WPF visual
        double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / fixedPage.ActualWidth, capabilities.PageImageableArea.ExtentHeight / fixedPage.ActualHeight);

        //Transform the Visual to scale
        fixedPage.LayoutTransform = new ScaleTransform(scale, scale);

        //get the size of the printer page
        var sz = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);

        //update the layout of the visual to the printer page size.
        fixedPage.Measure(sz);
        double x = capabilities.PageImageableArea.OriginWidth;
        double y = capabilities.PageImageableArea.OriginHeight;
        fixedPage.Arrange(new Rect(new Point(x, y), sz));
        fixedPage.UpdateLayout();
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top