Printing multiple images to the Fax virtual printer using PrintDocument on Win7&Vista results in corrupt TIFF

StackOverflow https://stackoverflow.com/questions/16221234

Question

I have an application that application uses PrintDocument to print multiple images as a single print job with one image per page. I am having an issue with a very specific but common configuration and am wondering how to correct it.

The code works without issue on any of the physical printers I have access to and the Microsoft XPS Document Writer on all Desktop Windows OSes. However printing to the Fax virtual-printer (the one that comes standard on Windows operating systems) only works on Windows XP and Windows 8. When I print to the Fax printer on Windows Vista or Windows 7, it indicates it prints successfully; but, if there was more than one page and you open the .tif image that is created Windows Photo Viewer says

Windows Photo Viewer can't open this picture because the file appears to be damaged, corrupted, or is too large.

That message is the one from Windows 7, the text may be slightly different on Vista. If there is only a single image (thus a single page) it works fine.

If the fax is sent, it comes out blank. I have also have tried opening the .tif image in GIMP and processing it with ImageMagick both of which failed indicating it was a bad .tif file.

This is the code that produces the issue, some robustness has been removed to allow for a more concise example.

internal void Print( string printerName )
{
    PrintDocument printDocument = new PrintDocument
        {
            PrinterSettings = new PrinterSettings {PrinterName = printerName}
        };

    IEnumerable<string> filesToPrint = new[]{"File1.png", "File2.png"};

    IEnumerator<string> enumerator = filesToPrint.GetEnumerator();
    enumerator.MoveNext()

    printDocument.PrintPage += (sender, args) =>
        {
            string fileName = enumerator.Current;

            using (var img = System.Drawing.Image.FromFile(fileName))
            {
                args.Graphics.DrawImage(img, args.PageBounds);
            }

            var moveNext = enumerator.MoveNext();

            args.HasMorePages = moveNext;

            if (!moveNext)
            {
                enumerator.Dispose();
            }
        };

    printDocument.Print();
}

Is this simply an issue with the Fax printer on those operating systems or is there something wrong with the above code? How might I resolve this issue?

This Microsoft hotfix does not specifically mention Faxing but does have the right error message, so I tried applying it. It made no difference.

Was it helpful?

Solution

I pursued this in the Microsoft Partner Support Community. The ultimate reply there was that they have confirmed the issue and the "escalation engineers are working at this issue."

The workaround I came up with myself is to print using System.Printing rather than the System.Drawing.Printing.

internal override void Print(string printerName, string baseFilePath, string baseFileName)
{
    using (var printQueue = GetPrintQueue(printerName))
    {
        XpsDocumentWriter xpsDocumentWriter = PrintQueue.CreateXpsDocumentWriter(printQueue);

        IEnumerable<string> filesToPrint = GetFilesToPrint(baseFilePath, baseFileName);

        PrintUsingCollator(xpsDocumentWriter, filesToPrint);
    }
}

private static void PrintUsingCollator(XpsDocumentWriter xpsDocumentWriter,
                                       IEnumerable<string> filesToPrint)
{
    SerializerWriterCollator collator = xpsDocumentWriter.CreateVisualsCollator();

    collator.BeginBatchWrite();

    foreach (var fileName in filesToPrint)
    {
        Image image = CreateImage(fileName);

        ArrangeElement(image);

        collator.Write(image);
    }

    collator.EndBatchWrite();
}

/// <remarks>
/// This method needs to be called in order for the element to print the right size.
/// </remarks>
private static void ArrangeElement(UIElement element)
{
    var box = new Viewbox {Child = element};

    box.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
    box.Arrange(new Rect(box.DesiredSize));
}

System.Printing is a newer API based on WPF. The down side to it in this particular case is that it is memory usage. Because System.Windows.Controls.Image is GC-ed (where as System.Drawing.Image requires explicit disposal) and I am loading relatively large images, it does seem to thrash memory usage a bit and ultimately be a bit slower on large jobs.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top