Exporting lines drawn by mouse to SVG

Hello,

I’ve been trying to make a Processing script that:

  1. Draws a line when the mouse is pressed .
  2. Exports these lines to an .svg file.

Here is my code:

Code
import processing.svg.*;

// setup runs before the main loop
void setup() {
  size(1400,800);
  beginRecord(SVG, "Filename_new.svg"); // starts recording everything on the canvas to a named svg file.
}

// the main loop
void draw() {
   stroke(0); //sets stroke color
   if (mousePressed == true) {
    line(mouseX, mouseY, pmouseX, pmouseY);
  }
}

void keyPressed() { //When a key is pressed, stop recording the SVG and exit.
  endRecord();
  exit();
}

The program draws a line whenever the mouse button is pressed. When a key is pressed, it exits the program and saves the result to an .svg file. However, the output .svg file is empty.
I did some research and found this forum post which pointed out that the method I am using is likely overwriting the output every frame (kudos to glv).

Any ideas for how to implement this? I’m going to try the following:

  1. Storing vertex input during the draw() loop in an array.
  2. Storing those arrays in another array so we have distinct lines.
  3. Recording everything just before exit.

I am open to thoughts, questions, and suggestions.
Thanks.

1 Like

Hello @aFewScrewsLoose,

Save the points (PVectors easy to work with) and redraw them all at once in a loop.

Partial example:

import processing.svg.*;

PVector [] p0 = new PVector [1000];  // pMouse (x, y) PVector
PVector [] p1 = new PVector [1000];  // mouse (x, y) PVector

// setup runs before the main loop
void setup() {
  size(800, 800);
  
  // Initialize
  for(int i = 0; i<1000; i++)
    {
    p0[i] = new PVector(0, 0);
    p1[i] = new PVector(0, 0);
    }
  }

int i = 0;

// the main loop
void draw() {
   stroke(0); //sets stroke color
   if (mousePressed == true) 
    {
   
   // Add code to save point in PVector arrays
     
    //line(mouseX, mouseY, pmouseX, pmouseY);
    i++;
    }

  // Add code to iterate through the arrays and draw the saved lines

  }

I left some work to challenge you!

This is a very quick exploration as a proof of concept that worked.

:)

Hey, quick response!
I hadn’t thought to use PVectors, so I’ll definitely give them a look.
I’ll post my implementation later.

PVectors are an easy way to set and work with x, y (and z) points.
Easy to work with once you wrap you head around them.

You could always use arrays only (one or two dimensional) to store this data.

Keep it simple (what you understand) and then build and improve on that.

:)

Hi
Here is how to export PDF and SVG

I’ve made an attempt at implementation, but I’m getting errors and I’m not super proficient with Java.

Here is the complete code:

Code -- All
import processing.svg.*;

//Create global variables
PGraphics svg;
int canvasW = 1400;
int canvasH = 800;
ArrayList<ArrayList<PVector>> group;
ArrayList<PVector> line;

//Settings (here because we may want variable canvas size)
void settings() {
  size(canvasW,canvasH); //set canvas size
}

// setup runs before the main loop
void setup() {
  svg = createGraphics(canvasW, canvasH, SVG, "Filename_new.svg"); //initialize the object we will record our .svg to.
}

// the main loop
void draw() {
   stroke(0); //sets stroke color (there may be a better place for this
   if (mousePressed == true) {
    line(mouseX, mouseY, pmouseX, pmouseY); //visual feedback for the user
    line.add(new PVector()); //add a new PVector containing the mouse_pos coordinates to an Array List ('line')
  }
}

void mouseReleased() {
  // add the ArrayList 'line' as an entry in ArrayList 'group'
  // clear the contents of line
  group.add(line); // Need to watch this one, it might make a shallow copy when we want a deep one.
  line.clear();
}

void keyPressed() { //When a key is pressed, stop recording the SVG and exit.
  noLoop();
  svgRecord();
  exit();
}

void svgRecord() {
  svg.beginDraw();
  svg.background(128,0,0);
  for (int i = 0; i < group.size(); i = i+1){
    svg.beginShape();
    for (int j = 0; j < group.get(i).size(); j = j+1) {
      svg.curveVertex(group.get(i).get(j).x,group.get(i).get(j).y);
    }
    svg.endShape();
  }
  svg.dispose();
  svg.endDraw();
}

And here is the code that’s throwing an error:

Code -- The Issue
// the main loop
void draw() {
   stroke(0); //sets stroke color (there may be a better place for this
   if (mousePressed == true) {
    line(mouseX, mouseY, pmouseX, pmouseY); //visual feedback for the user
    line.add(new PVector()); //add a new PVector containing the mouse_pos coordinates to an Array List ('line')
}
}

More specifically,

line.add(new PVector()); //add a new PVector containing the mouse_pos coordinates to an Array List ('line')

This line throws a NullPointerException. A cursory search on geeksforgeeks tells me that it might be caused by one of these:

  • Invoking a method from a null object.
  • Accessing or modifying a null object’s field.
  • Accessing or modifying the slots of null object, as if it were an array.

I am not sure how to troubleshoot this, but I think the issue is with the new PVector() snippet. For reference, I am following this example, specifically the last line of this passage:

// Declaring the ArrayList, note the use of the syntax "<Particle>" to indicate
// our intention to fill this ArrayList with Particle objects
ArrayList<Particle> particles = new ArrayList<Particle>();

// Objects can be added to an ArrayList with add()
particles.add(new Particle());

Any thoughts on this syntax?

P.S.
@jafal
Thanks for the source, I’m not sure it fits my current strategy but I’ll keep it in mind.

Take a look here:
ArrayList of objects / Examples / Processing.org

Instead of balls create an empty ArrayList of PVectors in setup().

You don’t have the co-ordinates in the PVector.

I always start simple and build on that.
Consider just storing the PVectors for now and drawing lines in a for loop.

void svgRecord() 
  {
  PGraphics svg = createGraphics(width, height, SVG, "output.svg");
  svg.beginDraw();
  svg.stroke(255, 0, 0);
  svg.line(0, 0, width, height);              // This works!
  for (int j = 1; j < line.size(); j++)       
    {
    // Your line
    }
  svg.endDraw();
  }

Later you can deal with shapes or create a PShape.

Your approach with shape may very well work… it did not initially when testing.
I throttled back to simply first to get a working example to build on first

Example here of drawing lines from last point to current point:
Vertex Trail with fading alpha possible?

:)