Geertjan's Blog

  • March 6, 2015

Rendering Music Notation in PDF Files on the Java Desktop

Geertjan Wielenga
Product Manager

It turns out to be pretty tricky to render music notation in PDF files in a Java desktop application. The upper part of the image below shows what Apache PDFBox makes of my PDF with music notation, below that you see the correct rendering in Acrobat PDF Reader:

Here's the PDFBox code for the above:

InputStream inputStream;
try {
inputStream = FileUtil.toFileObject(pathToPDFFile).getInputStream();
SwingController controller = new SwingController();
SwingViewBuilder factory = new SwingViewBuilder(controller);
JPanel viewerComponentPanel = factory.buildViewerPanel();
add(viewerComponentPanel, BorderLayout.CENTER);
controller.openDocument(inputStream, "", "");
} catch (FileNotFoundException ex) {

Next, let's look at a JavaFX solution, provided by this blog entry:

Possibly I haven't used PDFBox or JPedal-technologies correctly and the problem isn't with these libraries but with my lack of understanding of how to apply them to this scenario. 

So, finally, not having found any other way of achieving my goal, I used LilyPondTool for JEdit:

The above is a PDF generated via LilyPond and rendered in NetBeans via an embedded "DockablePdfViewer", which is based on JPedal, which is also part of LilyPondTools. After adding LilyPondTools as a JAR to my project, as well as JEdit itself, together with quite a few other JARs, the only code I needed to provide myself, turned out to be the following, after a lot of trial and error, in my MultiViewElement:

jEdit.setProperty("options.lilytool.pdf.follow-caret", "true");
DockablePdfViewer dpv = new DockablePdfViewer();
add(dpv, BorderLayout.CENTER);

A couple of sneaky tricks were needed to circumvent JEdit's own protocol for finding images:

@ServiceProvider(service = URLStreamHandlerFactory.class)
public class JEditResourceStreamHandlerFactory implements URLStreamHandlerFactory {
public URLStreamHandler createURLStreamHandler(String protocol) {
if (protocol.equals("jeditresource")) {
return new LilyPondToolHandler();
return null;
private static class LilyPondToolHandler extends URLStreamHandler {
protected URLConnection openConnection(URL u) throws IOException {
return new LilyPondConnection(u);
private static class LilyPondConnectionextends URLConnection {
private ByteArrayInputStream is = null;
public LilyPondConnection(URL url) throws UnsupportedEncodingException {
String file = url.getPath().replace("/LilyPondTool.jar!/", "");
Image image = ImageUtilities.loadImage(file);
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write((RenderedImage) image, "png", os);
is = new ByteArrayInputStream(os.toByteArray());
} catch (IOException ex) {
public void connect() throws IOException {
public InputStream getInputStream() throws IOException {
return is;

At the end of the day, I can now display music notation in PDF files in NetBeans IDE. The dependency graph is a bit too impressive though and a lighter solution would be preferable:

One other problem is that not all of the JARs shown above are in a Maven repo, i.e., I have them in my local repo only. 

Since PDF music notation files can be rendered via LilyPond, the basis for a complete LilyPond integration for NetBeans is not inconceivable.

I'm working on that here:


Join the discussion

Comments ( 3 )
  • guest Friday, June 12, 2015

    The official released version (1.8.9) has problems with certain fonts due to flaws of java awt. The unreleased 2.0 version does its own font rendering. If you could point me to the actual PDF, I can test whether it works with 2.0. (I am an Apache PDFBox committer and I use netbeans since the 90ies!)

  • Geertjan Monday, June 15, 2015

    OK, great to hear. Drop me a mail at geertjan dot wielenga at oracle dot com and let's discuss.

  • guest Thursday, January 21, 2016

    OpenViewerFX is now fully setup on Github so you should be able to add the dependency very easily in future.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.