PDF saving: how to open a window to choose path and specify a name

hello All,
I would like to know if there is a way/command to choose a path and a name every time I choose to save a PDF while my sketch is running (Processing desktop on a Mac). like It is done in every known software or app ?
thanx

1 Like

Is this what you’re looking for? selectOutput() / Reference / Processing.org

thanx @sterretje , maybe I am missing something but it seems that this works only with an already existing file but do not create a new file when called

You can combine it with something else. I’m very new to Processing, but below makes use of createWriter() / Reference / Processing.org to create a file; just type the filename in the input box (highlighted in blue)

image

code

PrintWriter pw;


void setup() {
  selectOutput("Select a file to write to:", "fileSelected");
}

void fileSelected(File selection) {
  if (selection == null) {
    println("Window was closed or the user hit cancel.");
  } //
  else
  {
    println("User selected " + selection.getAbsolutePath());

    pw = createWriter(selection.getAbsolutePath());
    pw.println("Hello World");
    pw.flush();
    pw.close();
    exit();
  }
}

How to write a PDF is something else that I don’t know.

in my case I am looking for exporting Vector graphics as PDF or SVG. maybe there Is a function in pure java for this ?

Google found e.g. this :wink: PDF Export / Libraries / Processing.org

code of one of the examples merged with previous example

import processing.pdf.*;

void setup() {
  selectOutput("Select a file to write to:", "fileSelected");
}

void fileSelected(File selection) {
  if (selection == null) {
    println("Window was closed or the user hit cancel.");
  } //
  else
  {
    println("User selected " + selection.getAbsolutePath());

    PGraphics pdf = createGraphics(300, 300, PDF, selection.getAbsolutePath());
    pdf.beginDraw();
    pdf.background(128, 0, 0);
    pdf.line(50, 50, 250, 250);
    pdf.dispose();
    pdf.endDraw();
    exit();
  }
}

This indeed writes a PDF

You will have to play with the other examples.till you find something that works for you.

thank you @sterretje for your help, sorry but I have to admit that I am having a hard time implementing this. I don’t really understand how the fileSelected(File selection) works without initiating “selection” and what is “File” type. I am not used to java.
my code looks something like this:

boolean rec=false;
void setup(){
  size(800, 800);
}

void draw() {
  if (rec=true) {
    beginRecord(PDF, "FileName.pdf");
  }

  drawTheThing();

  if (rec=true) {
    endRecord();
    Rec=false;
  }
}


void drawTheThing() {

  //
  //
}

// saving the PDF when ready using the key 'R'

if (key =='R') {

  rec=true;
}

I would like to have the option to choose the path and the name every time I need it by opening a dialog window.

I think that a simple task as this should not be so complicated !! :thinking: but thank you @svan, I will take time to play with the code you provided.
have a nice one

If you think this is complicated, you should see the alternatives :wink:

I really believe you :grinning:

Personally, I would try to use the technique suggested by @sterretje. It’s easier than what I posted and really does work. Perhaps we can help you get his technique to do what you want it to do.

@svan well I am a noob in java and any help is much aprreciated!

I don’t understand why the method suggested by @sterretje won’t work. First create a file name and location then immediately create your .pdf there. What is giving you a problem with this approach?

I would like to have the option to choose the path and the name every time I need it by opening a dialog window.

Perhaps we need to put a button on your window which will take you to the dialog every time you select it. Would the following interface work for your project?

import processing.pdf.*;

Button _select;
Button _quit;

color BLUE = color(64, 124, 188);
color LTGRAY = color(185, 180, 180);
color YELLOW = color(245, 250, 13);
color RED = color(255, 0, 0);
color BLACK = color(0, 0, 0);
color WHITE = color(255, 255, 255);

final int _wndW = 400;
final int _wndH = 250;

class Button {
  float x, y, w, h;
  String title;
  color btnColor;
  color txtColor;
  float txtSize;
  // Constructor
  Button(int xpos, int ypos, float wt, float ht, String titleStr, color bkgrnd, color forgrnd, float txtSz) {
    x = xpos;
    y = ypos;
    w = wt;
    h = ht;
    title = titleStr;
    btnColor = bkgrnd;
    txtColor = forgrnd;
    txtSize = txtSz;
  }

  void display() {
    fill(btnColor); // button color
    noStroke();
    rect( x, y, w, h); // rounded rect
    fill(txtColor); // text color
    textSize(txtSize);
    textAlign(CENTER, CENTER);
    text(title, x, y - 3, w, h);
  }
}

void fileSelected(File selection) {
  if (selection == null) {
    println("Window was closed or the user hit cancel.");
  } else {
    println("User selected " + selection.getAbsolutePath());
    PGraphics pdf = createGraphics(300, 300, PDF, selection.getAbsolutePath());
    pdf.beginDraw();
    pdf.background(128, 0, 0);
    pdf.line(50, 50, 250, 250);
    pdf.dispose();
    pdf.endDraw();
    exit();
  }
}

void setup() {
  size(_wndW, _wndH);
  background(BLUE);
  _select = new Button( 30, 30, 160, 30, "SelectFile...", LTGRAY, BLACK, 18.0);
  _quit = new Button(_wndW - 100, 30, 60, 30, "Quit", LTGRAY, BLACK, 18.0 );
}

void draw() {
  _select.display();
  _quit.display();
}

void mousePressed() {
  if ((mouseX >= _select.x) && (mouseX <= _select.x + _select.w) && (mouseY >= _select.y) && (mouseY <= _select.y + _select.h)) {
    println("You hit select btn.");
    selectOutput("Select a file to write to:", "fileSelected");
  }
  if ((mouseX >= _quit.x) && (mouseX <= _quit.x + _quit.w) && (mouseY >= _quit.y) && (mouseY <= _quit.y + _quit.h)) {
    exit();
  }
}

@svan well, I have a code with a lot of parameters, I play with colors, shapes, randomness, etc… once I am satisfied with a result I would like to save it. all of this should stay within the draw() function as in the code I shared. I am not using PGraphics , only beginRecord function. as I said I am not very familiar with java and I only use native processing functions, so I am having trouble understanding what I am doing when it is totally new for me !

@svan for the buttons I am using ControlP5 library

No problem with cp5 buttons. Can you post code for the interface so we can see what you are attempting? For example, there was no button on the code that you posted.

draw() is moving at a default speed of 60 frames per second, so I’m not sure you can do what you have proposed in the minimal example posted. If you use noLoop() then you can do something like this:

import processing.pdf.*;

void setup() {
  size(400, 400);
  noLoop();
 // Change this to reflect your system
  beginRecord(PDF, "/Users/yourName/Desktop/filename.pdf");
}

void draw() {
  // Draw something good here
  line(0, 0, width/2, height);
  endRecord();
}

I’m guessing that you don’t want to save every file in the same place.

@svan
my code is something like this:

import processing.pdf.*;
import controlP5.*;
ControlP5 cp5;
boolean Rec;


void setup() {

  size(800, 800);
  cp5.addButton("Rec")
    .setPosition(500, 10)
    .setSize(60, 10)
    .setLabel("Save PDF")
    ;
}


void draw() {
  if (Rec) {
    // file name and location are to specify here
    // selectOutput("Select a file to write to:", "fileSelected");
    beginRecord(PDF, "filename.pdf");
  }

  drawAllTheThings();

  if (Rec) {
    endRecord();
    Rec=false;
  }
}


void drawAllTheThings() {
  //
  // all the things
  //
}


public void Rec() {

  Rec=true;
  redraw();
}

I think you may not be able to use the approach that you just outlined. Personally, I think you would be better to do your experimenting somewhere else other than the draw() loop. You could create the image elsewhere and have it displayed in the loop, then when you like what you have record it. Getting a fileName and location in a fast moving draw() loop is fraught with problems in my opinion.

@svan ok, I see. I will consider a different approach then.

See if something like this would work. You can do all of your experimenting in the function drawLines(). The output from this will be called in the draw() loop. When you get ready to save it as a .pdf file first set the fileName and location with the ‘Select Output’ button, then immediately press the ‘p’ (lower case) key which will set record to true as long as it has a fileName to work with. You should then find the .pdf file wherever you saved it.

import processing.pdf.*;
import controlP5.*;

ControlP5 cp5;

int cols, rows;
int spacing = 30;

boolean recordPDF = false;
String filePathStr = "";

void drawLines() {
  for (int i = 0; i < cols; i++) {
    for (int j = 0; j < rows; j++) {
      int x = i*spacing;
      int y = j*spacing;
      line(x, y, x+30, y+30);
    }
  }
}

void setup() {
  size(800, 800);
  cp5 = new ControlP5(this);
  cp5.addButton("output")
    .setPosition(30, 10)
    .setSize(130, 30)
    .setLabel("Select Output")
    ;

  cols = width/spacing;
  rows = height/spacing;  
}

void draw() {
  if (recordPDF) {
    if (filePathStr.length() > 0){
    beginRecord(PDF, filePathStr);
    }
  }

  background(255);
  strokeWeight(2.0);
  drawLines(); 

  if (recordPDF) {
    endRecord();
    recordPDF = false;
    println("Printed pdf.");
  }
}

void keyPressed() {
  if (key == 'p') {
    recordPDF = true;
  }
  if (key == 's') {
  // Change this line if you decide to keep a .png copy
    saveFrame("/Users/yourName/Desktop/pdfimg.png");
  }
}

void fileSelected(File selection) {
 if (selection == null) {
    println("Window was closed or the user hit cancel.");
  } else {
    println("User selected " + selection.getAbsolutePath());
    filePathStr = selection.getAbsolutePath();
  }
}

void output(){
  selectOutput("Select a file to write to:", "fileSelected");
}