[HOWTO] Print with Juce


#1

Hi all,

Here’s a tutorial for printing with Juce.
First of all, as you may know, Juce Graphics is all vector based.
The vector drawing operations you perform on a Graphics object are then simplified to basic primitives, and applied to a LowLevelGraphicsRenderer.

This renderer can be based on an image (typically for a window on screen, or an offscreen bitmap), or using hardware accelerated primitive rendering (OpenGL for one, still not done).

One of these low level renderer is a PostScript renderer, and you’ll need to use this renderer to render your wonderful application graphic to an horrible washed ink-based print.

When you create this renderer, you’ll give a reference to the output stream you’ll later send to the printer, the document title, and the total width and height for the rendered page in arbitary units.

You’ll then create the Graphics object with this renderer, and perform your rendering as usual with your paint method.

Then, if everything goes well, you’ll get an output EPSF stream that you’ll need to send to the printer, through the drivers.

From now, things are getting more complex:
[list]
[*] Under Windows, you’ll have to use code like this:

[code]
void printEPSStream(const OutputStream & stream, const String & printerName, const String & documentName)
{
HANDLE hPrinter = 0;
DOC_INFO_1 doc = { 0 };
doc.pDocName = documentName;
doc.pDatatype = “RAW”;
if( OpenPrinter(printerName, &hPrinter, 0) )
{
// Start a document.
if( StartDocPrinter(hPrinter, 1, (BYTE*)&doc) )
{
// Start a page.
MemoryOutputStream * memStream = dynamic_cast<MemoryOutputStream*>(&stream);
if( memStream && StartPagePrinter(hPrinter) )
{
DWORD dwWritten = 0;

              WritePrinter(hPrinter, memStream->getData(), memStream->getDataSize(), &dwWritten);
        }
        EndDocPrinter(hPrinter);
    }
    ClosePrinter(hPrinter);
}

}
[/code][/]
[
] Under Linux, you’ll simply have to pipe the outputStream to the lpr program with this code (don’t used NamedPipe as they are Fifo not pipe):

[code]
void printEPSStream(const OutputStream & stream, const String & printerName, const String & documentName)
{
MemoryOutputStream * memStream = dynamic_cast<MemoryOutputStream*>(&stream);
if (!memStream) return;
String processName = “lpr -P”+ printerName;
FILE * outputPipe = popen(processName.toUTF8(), “w”);

if (outputPipe != NULL)
{
     fwrite(memStream->getData(), 1, memStream->getDataSize(), outputPipe);
     pclose(outputPipe));
}

}
[/code][/]
[
] I’m not sure about MacOSX, but I guess, the posix way should do it too.[/*][/list]

Concerning the printerName, there is no cross platform code already present. Under Window you’ll use EnumPrinters, under Linux you’ll have to parse /etc/printcap, and under Mac, well I’ve no idea.

Hope it helps.


#2

Here is a list of current limitations to Juce printing code:

Cons:
[list]
[] Currently, the EPSF renderer scales the rendered output to 750x520 (deducing the scale factor from totalWidth & totalHeight you’ve given). Everything is not vector based (especially images), so they might appear distorted.[/]
[] Unsupported methods are all methods using transparent colors (like fillAlphaChannelWithColour, fillAlphaChannelWithGradient, fillAlphaChannelWithImage that doesn’t work at all), and fillPathWithGradient (which fills the path with the average color of the gradient)[/]
[] Because it’s so low level, the text is printed as path. This means that if you are using PDFCreator, the text won’t be searchable in the resulting PDF file. As a fallback solution would be to use the hack code I’ve posted a while ago (PM me for details).[/]
[] Only one page, thus this means that layout code will have to be included somewhere, probably in the paint() method…[/]
[] API not finalized, as you can see, it’s missing the cross platform outputStream => printer code (and of course, printer selection and dialog box)[/]
[] So bad gradient aren’t working, this means that most SVG code will print badly.[/][/list]

Pro:
[list]
[] It’s in the code repository, this mean that it’ll get better and better as time goes on[/]
[] Limitation to gradient might disappear soon (maybe by approximating gradient by colour lines or small rectangle-point array ? it’s WIP)[/][/list]

Future devs:
[list]
[] Text rendering might get into the LowLevelRenderer primitive, so the PDF output could get sense[/]
[] Alpha colour isn’t specified in EPS. A good solution could be to consider plain white as default color, (after all, you rarely print on black paper) and drop alpha here. Anyway, work has still to happen here ?[/]
[] A PrinterStream for printing the resulting stream on destruction ?[/][/list]