I might be a bit over my head, apologies for the semi-long sketch and wall-of-text. I’m really puzzled by this!
I have a sketch with a PDF export that works great on it’s own, but that just saves a file in the sketch folder. So I wanted to add a file selector (selectOutput), but that turned out to be not so easy…
I’ve kind of narrowed it down (and kind of not). I found a work-around of sorts and made this small (well, small-ish) stand-alone sketch to demonstrate. It works some, maybe most of the time but not always. Not to mention that this work-around doesn’t work at all in my main sketch that I want to use it in.
The main thing to look at here is in the mouseClicked() function, and the two exportToPDF() functions.
(In my main sketch I don’t use mouseClicked(), nor have these button classes like here, so there’s a few differences).
In short, the work-around was to create a dummy PDF file before calling selectOutput, and then make the real PDF file. Otherwise I’d always get a NullPointerException (and usually several lines of errors or warnings). I still get the NPE some of the time.
If I cancel out of the file dialog, I also get several lines of warnings but the sketch continues.
I suspected some of this could be due to the path name string containing the backslash character, which was not escaped(\\), but it didn’t matter if I used the file path at all.
Hopefully someone have some idea what’s going on, or a fix… Maybe there’s something I’m completely ignorant of.
Here’s the demo sketch:
Click to expand
/*  PDF export with file selector fail test
    2020.08.16 raron
*/
import processing.pdf.*;
import static javax.swing.JOptionPane.*;
PGraphics originalG;
PGraphics pdf;
// PDF size
int pdfWidth = 2100;
int pdfHeight = 2970;
int pdfPages = 4; // nr. of test pages
File PDFfile = new File("New.pdf");
// Processing window size
int wWidth  = 400;
int wHeight = 300;
// The buttons
verySimpleButton greenButton;
verySimpleButton redButton;
// Just some colors
color whiteCol = color( 200 );
color blackCol = color( 0 );
color bgCol    = color(  24,  24,  24 );
color greenCol = color(   0,  80,   0 );
color redCol   = color(  80,   0,   0 );
void settings()
{
  size(wWidth, wHeight);
}
void setup()
{
  originalG = g; // Save Processing default graphics renderer (afaik)
  greenButton = new verySimpleButton(  66, 120, 100, 50, greenCol );
  redButton   = new verySimpleButton( 232, 120, 100, 50, redCol );
}
void draw()
{
  background( bgCol );
  fill( whiteCol );
  textSize( 16 );
  text("Press a button to attempt PDF export", 30, 75);
  textSize( 12 );
  text("Green button without file selector always works", 40, 210);
  text("Red button with file selector sometimes mess up", 40, 240);
  
  // Button updates
  greenButton.display();
  redButton.display();
}
void mouseClicked()
{
  // This works regardless of dummy pdf or not
  if (greenButton.underMouse()) exportToPDF("test.pdf");
  // This sometimes fail
  if (redButton.underMouse()) 
  {
    // Apparently, one has to make a dummy pdf before the file selection dialogue
    // Or else it always fails (NullPointerException)
    // It still fails sometimes, or makes a messed up pdf file mixed with the dummy pdf.
    pdf = createGraphics(pdfWidth, pdfHeight, PDF, "dummy.pdf");
    usePDF();
    fill(greenCol); // might help to do something with the dummy pdf?
    textSize( 80 );
    text("DUMMY PDF", 100, 100);
    g.dispose();
    useOriginalG();
    delay(200); // Seems to help?
    selectOutput("Save file as", "exportToPDF", PDFfile);
  }
}
void exportToPDF(File selection)
{
  String PDFPathAndFile = selection.getAbsolutePath();
  
  // Odd that this works to print without escaping the backslashes in the path strings (Windows)?
  println("Absolute path     : " + PDFPathAndFile);
  
  showMessageDialog(null, "Will a PDF be exported?", "Not yet done...", INFORMATION_MESSAGE);
  exportToPDF(PDFPathAndFile); 
}
void exportToPDF(String filePath)
{
  pdf = createGraphics(pdfWidth, pdfHeight, PDF, filePath);
  // Start PDF export
  usePDF();
  fill( blackCol );
  textSize( 50 );
  // Some demo pages
  for (int p=0; p<pdfPages; p++)
  {
    if( p>0 ) PDFnextPage();
    text("TEST PAGE " + (p+1), pdfWidth/2, pdfHeight/2);
  }
  
  // End PDF export
  g.dispose();
  useOriginalG();
  showMessageDialog(null, "PDF file exported!", "Done!", INFORMATION_MESSAGE);
}
// Draw to pdf
void usePDF()
{
  g.endDraw();
  g = pdf;
  g.beginDraw();
}
// Start next PDF page
void PDFnextPage()
{
  PGraphicsPDF pdfg = (PGraphicsPDF) pdf; // get the pdf renderer
  pdfg.nextPage();
}
// Draw to processing window
void useOriginalG()
{
  g.endDraw();
  g = originalG;
  g.beginDraw();
}
class verySimpleButton
{
  int x,y,w,h;
  color baseColor, hoverColor, pressColor, edgeColor;
  
  verySimpleButton(int _bx, int _by, int _bw, int _bh, color _baseColor)
  {
    x = _bx;
    y = _by;
    w = _bw;
    h = _bh;
    baseColor  = _baseColor;
    hoverColor = lerpColor(baseColor, color(255, 255, 255), 0.2);
    pressColor = lerpColor(baseColor, color(255, 255, 255), 0.4);
    edgeColor  = lerpColor(baseColor, color(255, 255, 255), 0.6);
  }
  
  void display()
  {
    fill(baseColor);
    if (underMouse())
    {
      fill(hoverColor);
      if(mousePressed) fill(pressColor);
    }
    stroke(edgeColor);
    rect(x,y,w,h);
  }
  
  boolean underMouse()
  {
    if (mouseX>x && mouseX<x+w && mouseY>y && mouseY<y+h) return true;
    return false;
  }
}

 )  Probably not the most efficient way but it works (so far).
)  Probably not the most efficient way but it works (so far).