Copy PGraphics by value

edited February 2017 in How To...

Which is the best(fast) way to copy two PGraphics (P1 over P2) by value ?
P2 = P1 seems to copy by reference :(
Thanks.
cameyo

Answers

  • P1 = P2.copy() I guess?

  • Sorry, but i get an error:
    cannot convert from PImage to PGraphics

  • Then use this workaround - it's not perfect in that the transformation matrix, the styles etc will not be copied, but the pixel values will be :

    PGraphics createGraphics(PImage img, String render){
      PGraphics pg = createGraphics(img.width, img.height, render);
      pg.beginDraw();
      pg.copy(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height);
      pg.endDraw();
      return pg;
    }
    
  • Use it like this - P2 = createGraphics(P1);

  • I have already PGraphics P2 :(
    i'm trying to use a "for" with "pixels" property.

  • That's it? Simple - p2.copy(p1, 0, 0, p1.width, p1.height, 0, 0, p2.width, p2.height);
    Capitalise the p's yourself.

    Also note that if the two PGraphics are different sized, it will end up stretching/shrinking accordingly.

  • edited February 2017
    PGraphics p1;
    PGraphics p2;
    void setup()
    {
      p1 = createGraphics(100, 100);
      p2 = createGraphics(100, 100);
      p1.beginDraw();
      p1.ellipse(50, 50, 10, 10);
      p1.endDraw();
      p2.beginDraw();
      p2.ellipse(10, 10, 5, 5);
      p2.endDraw();
      p2.copy(p1, 0, 0, p1.width, p1.height, 0, 0, p2.width, p2.height);
      p1.save("p1.png");
      p2.save("p2.png");
      exit();
    }
    void draw () {
    }
    //copia.pde:13:0:13:0: ClassCastException: sun.java2d.SunGraphics2D cannot be cast to java.awt.Image  
    
  • This is a bit slow :-S

    void copyPGraphics(PGraphics a, PGraphics b)
    {
      // b = a;
      a.loadPixels();
      b.loadPixels();
      b.beginDraw();
      for (int i = 0; i < b.pixels.length; i++) 
      {
        b.pixels[i] = a.pixels[i];
      }
      //a.updatePixels();
      b.updatePixels();
      b.endDraw();
    }
    
  • edited February 2017 Answer ✓
    /**
     * PImage/PGraphics pixels[] copyTo() (v1.1.1)
     * GoToLoop (2017-Feb-08)
     * forum.Processing.org/two/discussion/20716/copy-pgraphics-by-value#Item_9
     */
    
    PGraphics pg;
    
    void setup() {
      size(500, 400);
      noLoop();
    
      pg = createGraphics(width, height); // same dimensions as canvas.
      pg.beginDraw();
      pg.background(#0000FF); // blue PGraphics.
      pg.endDraw();
    
      background(#FF0000); // red canvas
      copyImg(getGraphics(), pg); // make target PGraphics red too.
    }
    
    void draw() {
      background(pg); // PGraphics is indeed red.
    }
    
    static final void copyImg(final PImage src, final PImage tgt) {
      src.loadPixels();
      tgt.loadPixels();
    
      arrayCopy(src.pixels, tgt.pixels);
      tgt.updatePixels();
    }
    
    static final void copyPixels(final color[] src, final color[] tgt) {
      arrayCopy(src, tgt);
    }
    
  • @cameyo Why not stick to the PImage class's copy function? It's clearly easier, even if it is a bit slower. And when working with PGraphics, speed is generally not much of a concern.

  • arrayCopy(src.pixels, tgt.pixels); works well and is fast :)

  • Answer ✓

    New version 1.1.1 -> deleted src.updatePixels();. Completely unnecessary! =P~

  • @GoToLoop

    static final void copyPixels(final color[] src, final color[] tgt) {
      arrayCopy(src, tgt);
    }
    

    never used ;)

  • That was just an extra option when we just wanna re-using the pixels[] directly w/o loadPixels() & updatePixels() each time.

  • Answer ✓

    The solution assumes that both

    1) P2 and P1 exist
    2) P2 has the same number of pixels as P1

    I would prefer a more flexible solution that would handle these cases like this

    PGraphics p2, p1;
    
    void setup() {
      size(400, 200);
      textSize(18);
      textAlign(CENTER, CENTER);
      p1 = makeRandomGraphic(width/2, height);
    }
    
    /**
     Duplicate and return a graphic that is an exact replica of the 
     source graphic.
     If the dest graphic does not exist or does not match the source then 
     a new graphic is instantiated and returned else this method overwrites
     the image in the dest graphic.
     Expected usage would be
     dest = copyGraphics(src, dest);
    
     @param src the graphic to copy
     @param dest the pgraphic to overwrite (if possible)
     @return the duplicated graphic
     */
    PGraphics copyGraphics(PGraphics src, PGraphics dest) {
      if (dest == null || dest.width != src.width || dest.height != src.height) {
        dest = createGraphics(src.width, src.height);
        dest.beginDraw();
        dest.endDraw();
      }
      src.loadPixels();
      dest.loadPixels();
      arrayCopy(src.pixels, 0, dest.pixels, 0, src.pixels.length);
      dest.updatePixels();
      return dest;
    }
    
    PGraphics makeRandomGraphic(int w, int h) {
      PGraphics pg = createGraphics(w, h);
      noiseSeed(millis());
      float ns = 0.02;
      pg.beginDraw();
      pg.background(0);
      for (int i = 0; i < w; i++) {
        for (int j = 0; j < h; j++) {
          int cc = int(noise(i * ns, j * ns) * 200 + 55);
          pg.set(i, j, color(cc, 0, cc));
        }
      }
      pg.endDraw();
      return pg;
    }
    
    void draw() {
      background(0);
      if (p2 == null) {
        fill(255);
        String info = "Hit 'n' to get a new graphic on the left and 'c' to create a copy and display it on the right";
        text(info, width/2, 0, width/2, height);
      } else {
        image(p2, width/2, 0);
      }
      image(p1, 0, 0);
    }
    
    void keyTyped() {
      if (key == 'n')
        p1 = makeRandomGraphic(width/2, height);
      else if (key == 'c')
        p2 = copyGraphics(p1, p2);
    }
    
  • Great effort! if you can make PImage work in your application, then get() is all what you need to create a copy. With PGraphics you have to do it differently as shown here in this post. However PImage is not a substitute for PGraphics... Otherwise life would be easier I-)

    Kf

  • edited February 2017

    However PImage is not a substitute for PGraphics...

    My solution needs PImage only, b/c it is the parent class for PGraphics and even other types like Movie & Capture. \m/

    If the only thing we demand is a transfer of pixels[], there's no need to go beyond what PImage already offers. O:-)

  • then get() is all what you need to create a copy.

    @cameyo was asking for the fastest way to copy. 8-|
    get() clones a PImage rather than simply copying it to another existing 1. :-@

  • edited February 2017

    @GoToLoop Then why exactly is copy() slower?

  • The copy() method does a lot of calculation/work under the hood.

    On the other hand arrayCopy() uses a JVM native method to copy of a single block of memory to another location - can't copy an array faster than that. :)

  • @quark thanks for the info, was half expecting something like that.

Sign In or Register to comment.