Disposing of a previous call to beginRaw()

edited July 2017 in Library Questions

I want to save the current frame as PDF, but only if a button has been pressed in that frame as well. The examples (e.g. the "PDF Files from 3D Geometry (With Screen Display)" from https://processing.org/reference/libraries/pdf/ appear to do something similar, but are essentially different: they use a variable to then save the NEXT frame.

I'd like to do something like the sample from https://processing.org/reference/beginRaw_.html (below) - to call beginRaw() every frame, and call endRaw() only if a key was pressed - but if no key was pressed at the end of draw(), i'd like to dispose of the recording of the current frame. Since there is not call to something like "disposeRaw()", beginRaw() creates a new PDF file each frame.

import processing.pdf.*;

Boolean saveFrame = false;
void setup() {
  size(400, 400, P2D);
}

void draw() {
  beginRaw(PDF, "raw"+frameCount+".pdf");
  line(pmouseX, pmouseY, mouseX, mouseY);
  if (saveFrame == true) endRaw();
  else // disposeRaw();
}

void keyPressed() {
  if (key == ' ') {
    saveFrame = true;
  }
}

How would I dispose of PDF file creation for frames which already called beginRaw()?

Answers

  • edited July 2016
    /**
     * Efficient PDF Screenshot (rasterized) (v1.1)
     * GoToLoop (2016-Jun-21)
     *
     * forum.Processing.org/two/discussion/17253/
     * disposing-of-a-previous-call-to-beginraw/#Item_1
     */
    
    import processing.pdf.PGraphicsPDF;
    
    static final String PDF_NAME = "frame-";
    static final short ZEROS = 6;
    static final float BOLD = 1.5, FPS = 100;
    static final color STROKE = 0;
    
    PGraphics pdf;
    PImage canvas;
    
    void setup() {
      size(600, 400);
      smooth();
      frameRate(FPS);
    
      stroke(STROKE);
      strokeWeight(BOLD);
    
      pdf = createGraphics(width, height, PDF);
      canvas = createImage(width, height, RGB);
    }
    
    void draw() {
      line(pmouseX, pmouseY, mouseX, mouseY);
      frame.setTitle("Frame: " + frameCount);
    }
    
    void mousePressed() {
      if (mouseButton == CENTER)  pdfScreenshot();
      else                        background((color) random(#000000));
    }
    
    void keyPressed() {
      int k = keyCode;
      if (k == ' ' | k == ENTER | k == RETURN)  pdfScreenshot();
    }
    
    File getPdfPath() {
      return dataFile(PDF_NAME + nf(frameCount, ZEROS) + ".pdf");
    }
    
    void pdfScreenshot() {
      File pdfFile = getPdfPath();
      if (!pdfFile.canWrite())  pdfFile.getParentFile().mkdir();
    
      pdf.setPath(pdfFile.getPath());
      println(pdfFile);
    
      loadPixels();
      arrayCopy(pixels, canvas.pixels);
      canvas.updatePixels();
    
      pdf.beginDraw();
      pdf.image(canvas, 0, 0);
      pdf.dispose();
      pdf.endDraw();
    }
    
  • Very impressive - thanks!

    Your version uses image() to copy the recorded data, resulting in the PDF file to contain a rasterized version - and no longer scalable vector data.

    How would I modify your code, so that actual vector data gets exported (of the current frame)?

    Thanks!

  • edited July 2016
    /**
     * Efficient PDF Screenshot II (vectorized) (v1.00)
     * GoToLoop (2016-Jun-21)
     *
     * forum.Processing.org/two/discussion/17253/
     * disposing-of-a-previous-call-to-beginraw/#Item_3
     */
    
    import processing.pdf.PGraphicsPDF;
    import java.awt.Point;
    import java.util.List;
    
    static final String PDF_NAME = "frame-";
    static final short ZEROS = 6;
    static final float BOLD = 1.5, FPS = 100;
    static final color STROKE = 0;
    
    final List<Point> coords = new ArrayList<Point>();
    
    PGraphics pdf;
    color bg;
    boolean clearBg = true;
    
    void setup() {
      size(600, 400);
      smooth();
      frameRate(FPS);
    
      stroke(STROKE);
      strokeWeight(BOLD);
    
      pdf = createGraphics(width, height, PDF);
    }
    
    void draw() {
      if (clearBg) {
        clearBg = false;
        coords.clear();
        background(bg = (color) random(#000000));
      }
    
      if (pmouseX != mouseX | pmouseY != mouseY) {
        line(pmouseX, pmouseY, mouseX, mouseY);
        coords.add(new Point(mouseX, mouseY));
      }
    
      frame.setTitle("Frame: " + frameCount + "    Size: " + coords.size());
    }
    
    void mousePressed() {
      if (mouseButton == CENTER)  pdfRenderShot();
      else                        clearBg = true;
    }
    
    void keyPressed() {
      int k = keyCode;
      if (k == ' ' | k == ENTER | k == RETURN)  pdfRenderShot();
    }
    
    File getPdfPath() {
      return dataFile(PDF_NAME + nf(frameCount, ZEROS) + ".pdf");
    }
    
    void pdfRenderShot() {
      File pdfFile = getPdfPath();
      if (!pdfFile.canWrite())  pdfFile.getParentFile().mkdir();
    
      pdf.setPath(pdfFile.getPath());
      println(pdfFile);
    
      pdf.beginDraw();
      pdf.smooth();
    
      pdf.background(bg);
      pdf.stroke(STROKE);
      pdf.strokeWeight(BOLD);
    
      Point prev = coords.get(0);
      for (Point curr : coords) {
        pdf.line(prev.x, prev.y, curr.x, curr.y);
        prev = curr;
      }
    
      pdf.dispose();
      pdf.endDraw();
    }
    
  • edited June 2016

    Sorry for my late reply - was in transit.

    Your solution works fine for my initial example - thank you a lot for your energy and dedication!

    However, my actual usecase sadly is far more complex, making extended use of a variety of rendering libraries and techniques. It's not really an option to write my own PDF exporter (as this example might give the impression) - I simply don't have access to all required vector data and state changes.

    Which brings me back to my initial question: Do we need to write our own PDF exporter if we want to save the current frame? Is it only possible to save the upcoming frame? This seems so weird! It seems a minor, yet fundamental design flaw of that exporter.

    Wouldn't a dispose() function for the exporter solve this issue? Right now, we're forced to follow through on an export initiated with beginRaw() - which in most cases is wanted ;) But when trying to export the current frame, it seems too limited.

Sign In or Register to comment.