Export SVG from PGraphics

I have a doubt on how to export an SVG with the vector contents inside a PGraphics.

Here’s the deal, I’m doing some mouse interactivity(storing mouseClicks as vectors) that are stored in a PGrpahics that’s sending that image through spout.
When finished, i want to export that same PGraphics as an svg file.

i’ve tried the approaches from processing documentation. i’ve done the if(record) at the begining and end of draw. i’ve tried the to create two PGraphics, one SVG and the other a 3d and copy the content of one to the other, but this option is not available (CANNOT COPY TO SVG)…

so basically

ArrayList<Polyline> pLines;

PGraphics pgr;

void setup(){
  size(1200,960,P3D);
  hint(ENABLE_DEPTH_SORT);
  textureMode(NORMAL);

  spout=new Spout(this);
  spout.createSender("spout p55");

  pgr=createGraphics(width*2,height*2);

  pLines=new ArrayList();
}

void draw(){
 background(0);

  pgr.beginDraw();
  pgr.clear();
  for(Polyline p: pLines){
    p.display();
  }
  pgr.endDraw();

  spout.sendTexture(pgr);
  image(pgr,0,0,width,height);
}
1 Like

what you try insofar using
https://processing.org/reference/libraries/svg/index.html
what produces that error?


i know that concept look backward but might be what you wanted to do:

import processing.svg.*;
PGraphics pgr;
String file = "data/pgr.svg";
PShape getsvg;

void setup() {
  size(500, 500, P3D);
  make_pgr();
  getsvg = loadShape(file);
  println("move mouse over canvas and press key [r]");
}

void make_pgr() {
  pgr=createGraphics(width, height, SVG, file);
  pgr.beginDraw();
  //pgr.clear();
  pgr.background(200, 200, 0);
  pgr.translate(width/2, height/2);
  pgr.stroke(0, 200, 0);
  pgr.strokeWeight(5);
  pgr.line(0, 0, -width/2 + mouseX, -height/2 + mouseY);
  pgr.dispose();
  pgr.endDraw();
}

void draw() {
  shape(getsvg, 0, 0);               // you see the loaded SVG file, not the PGraphics
}

void keyPressed() {
  if ( key == 'r' ) { 
    make_pgr();   
    getsvg = loadShape(file);        // reload 
    println("saved: "+file);
  }
}

i have two different uses for the same pgr, syphon/spout output and save svg.

i’ve just tried

pgr = createGraphics(pgrWidth, pgrHeight, SVG, "saves/out3.svg");
....
if(record){
   pgr.dispose();
   record=false;
  }

and get

no loadPixels() for PGraphicsSVG

i guess i’ll have to do the main PGraphics an SVG and then raster it in a P2D/P3D PGr and broadcast that raster PGr

looking for how to raster vector files in processing

openFrameworks works this smoothly. i’ve used it to send a OPENGL fbo to syphon.

tex=fbo.getTexture();
fbo.draw(0,0,ofGetWidth(),ofGetHeight());
mClient.draw(50,50);
mainOutputSyphonServer.publishTexture(&tex);

another way to do this is to do all the work in the PGraphicsSVG and then raster it and copy it to a bitmap PGraphics. But don’t know how to raster this svg pg

Maybe I’m misunderstanding, but PGraphics don’t contain vector data – they are rastor only. I think that you need to either capture geometry from eg PShape or else trap individual rect / ellipse / line / etc calls and save them out to a generated svg as the calls are made – because their results are just pixels. This is how svg export works in the library examples:

hi jeremy

what i’ve understood about this documentation is that you can get two different kind of PGraphics, the usual raster and a vector one if you initiate it as an svg. i’ve tried both approaches.
once iniated all the process as an SVG PG but couldn’t raster it, by simply copying the vector PG to a raster PG, or using load pixels then copying the array to the raster target.

what i haven’t tried is placing the svg.dispose() in the Polyline object. but anyway it still misses the transposition for spout/syphon display that’s essential to the purpose of the program. cause i’m doing this to trace a complex surface for a videomapping, so i need to see in the projected surface what i’m doing and i need to save it as a vector for a posterior edit at my desktop.

1 Like

Ah, I see. I hadn’t looked at that before – thanks for pointing it out.

There is a whole lot of “nope()” in that source – the list of things you can’t do with it that you can do with the normal API is extensive.

these nopes are cute… LOL

looking at documentation i fou something very interesting, a clue for things to come

`boolean` `save(String filename)`

( begin auto-generated from PImage_save.xml ) Saves the image into a file.

after a long time got the solution to this issue. the answer is cloning the drawing methods from the pgr to the svg pgraph. the svg is called only once, when recording is triggered.

cloned the display methods, only changing the pgr to svg pgraph
cloned the draw functions, only changing the pgr to svg pgraph

svg pgraph is only activated through a trigger.

1 Like

Glad you found a solution!

Could you explain a bit more what you mean by “cloning” methods? I’m not understanding. What are you moving from where to where?

have both in the polyline and line object, since all the work/interactivity is really done in adding and calling the PVectors

i’ve got a

PGraphics pgr; //raster image
PGraphics svg; //vector image

runtime functions. i could have encapsulated the raster but prefered not to.
saveSvg is called by s cp5 bang

void draw() {
  background(32);


  pgr.beginDraw();
  pgr.background(0);
  for (int i=pLines.size()-1; i>=0; i--) {
    Polyline p=pLines.get(i);
    p.display();
  }

  for (int i=linhas.size()-1; i>=0; i--) {
    Linha l=linhas.get(i);
    l.display();
  }

  if (mouseX>pgrOrigin) {
    posX=int(map(mouseX, pgrOrigin, pgrOrigin+(pgr.width/2), 0, pgr.width));
    posY=mouseY*2;
    pgr.stroke(strokeColor);
    pgr.noFill();
    pgr.ellipse(posX, posY, 14, 14);
  }

  pgr.endDraw();


  syphon.sendImage(pgr);
  image(pgr, pgrOrigin, 0, pgr.width/2, pgr.height/2);
}

void saveSVG() {
  svg.beginDraw();
  for (int i=pLines.size()-1; i>=0; i--) {
    Polyline p=pLines.get(i);
    p.svgDisplay();
  }

  for (int i=linhas.size()-1; i>=0; i--) {
    Linha l=linhas.get(i);
    l.svgDisplay();
  }
  println("SVG record:BEGIN");
  svg.dispose();
  println("SVG record:END");
  svg.endDraw();
}

methods in each object

  void display() {
    pgr.beginShape();
    pgr.stroke(sColor);
    pgr.strokeWeight(sW);
    pgr.noFill();
    for (int i=vertexes.size()-1; i>=0; i--) {
      PVector v=vertexes.get(i);
      pgr.vertex(v.x, v.y);
    }
    if (state) {
      pgr.endShape(CLOSE);
    } else {
      pgr.endShape();
    }
  }
  
    void svgDisplay() {
    svg.beginShape();
    svg.stroke(sColor);
    svg.strokeWeight(sW);
    svg.noFill();
    for (int i=vertexes.size()-1; i>=0; i--) {
      PVector v=vertexes.get(i);
      svg.vertex(v.x, v.y);
    }
    if (state) {
      svg.endShape(CLOSE);
    } else {
      svg.endShape();
    }
  }

screenshot of the interface

1 Like