Loren on the Art of MATLAB

Printing in a Deployed Application 10

Posted by Loren Shure,

This week guest blogger Peter Webb continues his series of deployment-related posts with an article describing how printing works in a deployed application.

Contents

Introduction

With this post, I hope to answer some long-standing and frequently asked questions about how a deployed application generates hardcopy and why that process differs from printing in MATLAB. The differences are most evident in applications running under Microsoft Windows; thus the bulk of this post concerns printing on Microsoft Windows. Most of these issues simply aren't issues at all on the UNIX platforms.

Two Kinds of Printing

MATLAB's print command can send the graphics displayed in a figure window either to a file or a printer. MATLAB executes very different code for when preparing graphics for these two destinations. Printing to a file is the simpler process, as it effectively involves copying the pixels already displayed in the figure into a file on the disk. Printing to a printer requires MATLAB to send instructions to the printer to regenerate the figure's pixels inside the printer.

MATLAB figure windows render graphics using a mixture of C/C++ functions and Java classes and methods. MATLAB's C/C++ functions invoke the native platform's graphical APIs directly; these C/C++ functions comprise native mode Handle Graphics. MATLAB is evolving away from native mode graphics, because Java-based graphics are less platform-dependent, but certain functions have not yet made the transistion. On the Microsoft Windows platform, printing figure windows still requires calls to the native Windows API. UNIX platforms use Java, non-native mode, graphics to print.

Why does all this matter? Because applications generated with the MATLAB Compiler and the deployment tools cannot use native mode Handle Graphics. Without some kind of additional support, MATLAB applications deployed to computers running Microsoft Windows would not be able to print. The MATLAB Compiler hides this complexity behind the deployprint function, presenting a uniform API on both Microsoft Windows and UNIX systems. Deployed applications must use deployprint rather than print to send data to the printer:

    if ~isdeployed
        print
    else

        deployprint
    end

The isdeployed function only returns true when executed by a deployed application.

Note that deployprint cannot be used to print to a file, but only to send output to a printer. For printing to file, even in a deployed application, use print instead.

Printing Interactively in MATLAB

In MATLAB, printing is a four step process. In each step, you interact with a single function or dialog box:

  1. Begin printing, specify figure to print: print
  2. Set MATLAB-specific print options: printdlg
  3. Set platform-specific print options: the platform-specific print dialog box.
  4. Send the data to the printer: the MATLAB Cancel Print Job dialog box.

Step 1 creates a print job and initializes it with default data. Steps 2 and 3 optionally modify the defaults. Step 4 reads the settings in the print job and uses it to send image data and instructions to the printer. Together, these four steps make up the printing pipeline. In an interactive MATLAB session, MATLAB manages all four steps of the pipeline, but in a deployed application different programs manage different parts of the pipeline.

Printing from a Deployed Application

When a deployed application prints, the printing pipeline has an additional step:

  1. Begin printing.
  2. Set platform-specific print options.
  3. Generate bitmap file from figure.
  4. Set platform-specific print options.
  5. Send data to the printer.

The deployprint function manages the entire pipeline, but instead of using the Microsoft Windows printing API for the last two steps, as print does, deployprint delegates this responsibility to a separate program, PrintImage.exe. Since PrintImage cannot directly access the figure window data, deployprint invokes print to create a Microsoft Windows bitmap from the figure, and passes the name of the bitmap file to PrintImage.

Deployed applications use the MATLAB Common Runtime (MCR) rather than MATLAB to execute MATLAB functions. MATLAB functions executed by the MCR produce exactly the same results as when MATLAB executes those functions. However, PrintImage is not MATLAB, and though we've made every effort to duplicate MATLAB's behavior in PrintImage some differences are inevitable.

In both MATLAB and deployed applications, properties stored on the figure window affect the printed appearence of the figure window. For example, the PaperOrientation property determines if the figure prints in landscape or portrait mode.

Figure Properties and Printing

In an interactive session, MATLAB processes all of the figure properties relevant to printing. In a deployed application, the MCR processes all of the figure properties relevant to creating a bitmap (such as figure background color) and leaves the properties that position the image on the page for PrintImage to process.

Figure properties processed by PrintImage:

PrintImage endeavours to process these properties just as MATLAB would, but probably doesn't get it exactly right every time.

In addition to specifying the position and orientation of the printed figure, you can use the print preview dialog box to place header information on every printed page. In a deployed application, PrintImage, rather than MATLAB, processes the header data to produce the header text. Page header properties supported by PrintImage:

  • Date format
  • Font angle
  • Font name
  • Font size
  • Font weight
  • Margin
  • String

Like it does with the figure properties, PrintImage attempts to process header text just as MATLAB does.

Three Major Differences

  • Deployed applications print to a printer using deployprint and print to files using print. MATLAB uses a single function, print, for both types of printing.
  • Deployed applications print to a bitmap first, then send the bitmap to the printer. If the figure uses a vector renderer, such as Painters, the printed output may differ visually from the graphics displayed in the figure. Deployed application always print using a raster renderer.
  • Deployed applications format the figure data and the header text separately. The MCR renders the figure data to a bitmap, and PrintImage superimposes the header text on the bitmap as it sends the bitmap to the printer. This may cause the header text to be placed in a slightly different position on the page in a deployed application.

Frequently Asked Questions

Can't the Compiler substitute deployprint for print at compile time? No. The MATLAB Compiler, as a matter of policy, does not alter the executable code in any of the M-files that it packages for deployment. In part, we established this policy to ensure that the MATLAB Compiler does not introduce any bugs into your M-files, but we also recognize that this kind of substitution is impossible to implement with 100% accuracy. Calls to print could be hidden in strings passed to eval, or in anonymous function handles or passed in as function parameters at runtime. Rather than make promises we couldn't keep, we opted to require the use of isdeployed and deployprint as noted above.

Why does mlint warn about printdlg? This warning is out-of-date. In a future release it will be changed to indicate that deployed applications do support printdlg, but only the single-argument form of printdlg.

Why can't I print (using deployprint) to PDFs? Since deployprint uses print -dbmp to create the bitmap file, it explicitly ignores any output device specification passed in as an argument. However, you can use print -dpdf to create a PDF file in your deployed applications. For example:

  switch KindOfPrinting
      case 'Interactive'

          if ~isdeployed
              print;
          else
              deployprint;
          end
      case 'ToFile'
          % Here, device should be a string such as 'pdf', and

          % outputFileName a name like 'output.pdf'.
          print(['-d' device], outputFileName);
      otherwise
          disp(['Unrecognized printing mode: ' KindOfPrinting]);
  end

Why do my figures look different when printed? Printed output may differ from on-screen graphics if the figure uses the Painters renderer. You can ensure your on-screen and printed graphics always use a raster renderer by setting the figure to use the Z-buffer renderer:

  set(gcf, 'Renderer', 'zbuffer')

Or, you can preview the appearence of your figures in a deployed application by printing them (in MATLAB) to a bitmap, and then either viewing that bitmap on the screen or printing it. This command prints the current figure to a bitmap file named myfig.bmp.

  print -dbmp myfig.bmp

How can I print from the menu bar or toolbar of a deployed application? The default figure menu bar in a deployed application contains a single entry File. At the end of this menu is the selection Print.... Selecting Print... invokes deployprint and PrintImage. On the figure toolbar all deployed applications display a button containing a printer icon. Pressing this button sends the associated figure to the printer using deployprint and PrintImage.

How can I print from a shared library? Either use the figure's menu or toolbar to print interactively, or write your own function that calls deployprint and include that function in your compiled application. For example, this myprint function sends the given figure (specified by figure number) to the given printer (specified by name):

  function myprint(fig, printer)
    deployprint(['-f' num2str(fig)], ['-P' printer]);
  end

If you create this function in myprint.m and add it to your compiled application, you'll be able to call the myprint function from whatever code you link your shared library against.

The Future of Printing

When MATLAB abandons native mode Handle Graphics entirely, and supports Java-based printing on Microsoft Windows, deployprint and PrintImage will no longer be necessary. deployprint will simply call print (as it does now on Unix systems), and the printing-related mlint warnings will be modified or eliminated. Until then, however, you'll likely want to keep a copy of this posting handy if you deploy applications that target Microsoft Windows.

More to Come

Future posts will cover troubleshooting a deployed application (overcoming common failures), debugging and managing and organizing your code for deployment; if you've got a topic you'd like to hear more about, please let me know. In the meantime, you can refer to the documentation for the MATLAB Compiler or post follow-up questions here.

10 CommentsOldest to Newest

Loren,

thank you very much for writing about printing. The function printdlg is handy for deployed applications.

However, there are some little issues about printing:

1. I tried to print a figure containing an image and a title of it to a PDF. The image contains a pengin swimming in a bassin. A colored frame is drawn around the pengin. In the GUI, the contrast between the frame and the background is strong so the frame can be seen very well. The title does not appear in the GUI, but texts in GUIs are readable anyway. However, in the PDF the frame seems to be thinned and the text is somehow smeared.

2. The print preview is in English even on a machine with non-English Windows. Moreover, I get an error message in the DOS window when pressing the help button. This might confuse some users. Either the help button should be invisible in a deployed application or help should be implemented in another way.

It is easy to open a figure and let the user export an image or diagram from there. However, the user might try to use some functionality that does not work properly when the program is deployed. This does not only apply for the print preview. In Matlab it is possible to save a figure to a PDF and the resulting PDF looks good. However, when the program is deployed, trying to save (not to print) a figure to a PDF does not work and causes an error message in the DOS window. A simple, but not very elegant work around is discouraging users from trying to create PDFs.

I found out that it is possible to print PDFs with a good quality. The figure to be printed out or saved to the PDF is resized so its width is equal to the width of the paper (A4).

The frame around the object of interest is clearly visible. The figure property InvertHardCopy is set to “off” so a white frame is printed/ saved white.

The settings of the PDF printer are chosen in a way that the figure is not resized, but printed/ saved in its original size.

It seems that the only way to save a PDF file from a deployed application is printdlg. Everything else I have tried out so far causes error messages or does not work properly.

OkinawaDolphin,

Have you tried printing to PDFs from a deployed application using the PRINT command directly? I’ve compiled and run the toPDF function below on a Windows machine, and it generates a PDF file very similar (if not identical) to that created by an interactive MATLAB session.

function toPDF
knot;
print(gcf, ‘-dpdf’, ‘knot.pdf’);

Your point about the help button in the Print Preview dialog box is well taken. I’ll enter that as a bug into our bug-tracking system. Thanks for pointing that out.

Peter Webb,

I tried to generate a PDF document using print with a deployed program. There are several error messages in the DOS window. My Matlab version is R2007a. Is there any work around for the errors described below? What version did you compile your program with?

The error messages are:

Warning: See help sprintf for valid escape sequences.
> In graphics\private\ghostscript at 74
In print at 290
In SpeichereAbbildung at 94
In AlarmMaske\DruckknopfSpeichern_Callback at 522
In gui_mainfcn at 95
In AlarmMaske at 42
??? Error using ==> graphics\private\ghostscript at 74
Can not find the directory for Ghostscript in c:

Error in ==> SpeichereAbbildung at 92

Error in ==> AlarmMaske>DruckknopfSpeichern_Callback at 522

Error in ==> gui_mainfcn at 95

Error in ==> AlarmMaske at 42

??? Error using AlarmMaske(‘DruckknopfSpeichern_Callback’,gcbo,[],guidata(gcbo))
Error using ==> graphics\private\ghostscript at 307
Error using ==> graphics\private\ghostscript at 74
Can not find the directory for Ghostscript in c:

??? Error while evaluation uicontrol Callback

As I mentionned in a previous post on Steve blog: http://blogs.mathworks.com/steve/2008/09/19/blog-changes/
I really appreciate discussions concerning MATLAB Compiler. You give a good summary about the differences of appearance of a GUI when deployed or about the main things to be aware when we want to print from a standalone. I am sure technical support will have less phone calls thanks to these articles !
I’ve got 1 topic I’d like to hear more about: how standalones are affected by multithreading combined with explicit parallelism when executed against MDCS?
Thanks,
Aurélien QUEFFURUST

Well, I have tried creating PDFs with R2007b and it works fine. The PDFs can be saved with hgexport(). It isn’t necessary to use printdlg() or print().

I think the bloggers should be more specific about the Matlab version they refer to. Not all companies and universities purchase the newest release half a year.

@ OkinawaDolphin

there is a bug in MCR R2007a. matlab/sys/gs8x is not included in the MCR, Ghostscript will not run.

This bug was fixed as of R2007b

If you are using a previous version, copy the contents of the matlab/sys/gs8x directory into the MATLAB Component Runtime\v76\sys folder

Hi
I came across this when trying to discover how to access the z-buffer of a figure. We are trying to simulate simple output of the Kinect by rendering an object and then getting the depth map. The z-buffer should contain exactly what Im looking for but I cant find out how to expose that information. Is their a handle to it somewhere?

Aaron,

I’m not an expert on MATLAB’s graphics (I’m a compiler guy), but my sources indicate that the Z buffer data is transient and not available to MATLAB functions.

These postings are the author's and don't necessarily represent the opinions of MathWorks.