# PImage displays well but exports as empty file

**URL:** https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605
**Category:** Coding Questions
**Created:** [June 17, 2024, 2:18am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605 "2024-06-17T02:18:37Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![TellAJoke](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/tellajoke/32/18982_2.png) [@TellAJoke](https://discourse.processing.org/u/TellAJoke)
#### Post date: [June 17, 2024, 2:18am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605/1 "2024-06-17T02:18:37Z")

</div>

Hello. In this code snippet I create a canvas and draw on it using a shader. The created image displays nicely, but when exported the PNG file is empty. Exporting the canvas directly wont work either. When I do loadPixels() on the PImage it shows as empty too.

Any idea why the PImage is empty?

```auto
PShader shader;

void setup() {
  size(1080, 500, P2D);
  shader = new PShader (this, vertSrc, fragSrc);
}

void draw() {
  background(0);

  if (mouseX > 0 && mouseY > 0) {
    PImage img = getPhenotype(mouseX, mouseY, shader);
    image(img, 0, 0);
    if(mousePressed)img.save("img.png");
  }
}

PImage getPhenotype(float _w, float _h, PShader _shader) {
  int w = floor(_w);
  int h = floor(_h);

  PGraphics canvas = createGraphics(w, h, P2D);

  canvas.beginDraw();

  canvas.shader(_shader);

  canvas.rect(0, 0, canvas.width, canvas.height);

  canvas.endDraw();

  return canvas;
}

String[] vertSrc = {"""
#version 330 core
uniform mat4 modelview;
uniform mat4 projection;
in vec4 position;
in vec4 texCoord;
out vec2 uv;
void main() {
  uv = texCoord.xy;
  gl_Position = projection * modelview * position;
}
"""};

String[] fragSrc = {"""
#version 330 core
in vec2 uv;
out vec4 fragColor;
void main() {
  fragColor = vec4( length(uv-0.5) < 0.25 ? vec2(0.) : uv, 0.0, 1.0 );
}
"""};

```

_Snippet based on code by scudly on another of my posts_

Thanks for the help!

---

<div class="post-metadata">

### Author: ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)
#### Post date: [June 17, 2024, 2:40am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605/2 "2024-06-17T02:40:32Z")

</div>

Hello,

Try this:

```auto
    if(mousePressed) 
      {
      save("sketch.png");
      
      g.save("g.png");
      
      PImage pg = g.copy();
      pg.updatePixels();
      pg.save("test.png");
      println(pg.pixels.length);
      }

```

Worked here.

You may just have to add this to your code:

```auto
img.updatePixels();

```

`:)`

---

<div class="post-metadata">

### Author: ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)
#### Post date: [June 17, 2024, 2:46am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605/3 "2024-06-17T02:46:47Z")

</div>

I do it by keeping the type as `PGraphics` and passing that reference into `image()` and calling `.save()` on it. Alternatively, in `getPhenotype()`, also `createImage()` and fill it with `canvas.get()` and return that instead of the PGraphics.

OpenGL stores its images on the GPU rather than in system memory and Processing doesn’t always seem to know when it needs to copy the pixels over. Copying the pixels from video memory to system memory can be slow so they try not to do it unless it’s needed.

Also, you probably don’t want to trigger the save by reading a state variable in `draw()` since it will likely trigger many frames in a row saving the image over and over again. Safer to trigger it from a `mousePressed()` or `keyPressed()` callback.

---

<div class="post-metadata">

### Author: ![TellAJoke](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/tellajoke/32/18982_2.png) [@TellAJoke](https://discourse.processing.org/u/TellAJoke)
#### Post date: [June 17, 2024, 3:50am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605/4 "2024-06-17T03:50:33Z")

</div>

Thanks for the quick response 🙂  
That solution isn’t working for me though…

```auto
void draw() {
  background(0);

  if (mouseX < 1 || mouseY < 1) return;
  
  PImage img = getPhenotype(mouseX, mouseY, shader);
  image(img, 0, 0);

  if (mousePressed) {
    img.save("canvas.png");

    PImage toExport = img.copy();
    toExport.updatePixels();
    toExport.save("img.png");
  }
}

```

This is what you meant right? Still exporting an empty file on my end

---

<div class="post-metadata">

### Author: ![TellAJoke](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/tellajoke/32/18982_2.png) [@TellAJoke](https://discourse.processing.org/u/TellAJoke)
#### Post date: [June 17, 2024, 4:00am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605/5 "2024-06-17T04:00:58Z")

</div>

Thanks for the help 🙂  
The solutions don’t seem to be working on my end though

Using PGraphics object still exports an empty PNG, had even tried it already before creating the post

```auto
void draw() {
  background(0);

  if (mouseX < 1 || mouseY < 1) return;
  
  PGraphics canvas = getPhenotype(mouseX, mouseY, shader);
  image(canvas, 0, 0);
  
  if (mousePressed) {
    canvas.save("canvas.png");
  }
}

```

Using canvas.get() stops displaying the image altogether

```auto
PImage getPhenotype(float _w, float _h, PShader _shader) {
  int w = floor(_w);
  int h = floor(_h);

  PGraphics canvas = createGraphics(w, h, P2D);

  canvas.beginDraw();

  canvas.shader(_shader);

  canvas.rect(0, 0, canvas.width, canvas.height);

  canvas.endDraw();
  
  PImage toReturn = canvas.get(); // meant this right?

  return toReturn;
}

```

Thanks for the tip! But this was just a quick sketch to replicate the problem I’m getting on a larger project. Doing decent buttons on there

---

<div class="post-metadata">

### Author: ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)
#### Post date: [June 17, 2024, 4:43am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605/6 "2024-06-17T04:43:58Z")

</div>

The code below works for me if we just leave `PImage` out of it.

On the other hand, you most certainly don’t want to be creating a new PGraphics every frame. Every `createGraphics()` is allocating a new OpenGL frame buffer object and I don’t know how efficiently Processing / JOGL / your video driver is at cleaning them up.

```auto
PShader shader;
boolean bSaveImage = false;

void setup() {
  size(1080, 500, P2D);
  shader = new PShader (this, vertSrc, fragSrc);
}

void draw() {
  background(0);

  if (mouseX > 0 && mouseY > 0) {
    PGraphics img = getPhenotype(mouseX, mouseY, shader);
    image(img, 0, 0);
    if( bSaveImage ) {
      img.save("img.png");
      bSaveImage = false;
    }
  }
}

void mousePressed() {
  bSaveImage = true;
}

PGraphics getPhenotype(float _w, float _h, PShader _shader) {
  int w = floor(_w);
  int h = floor(_h);

  PGraphics canvas = createGraphics(w, h, P2D);

  canvas.beginDraw();
  canvas.shader(_shader);
  canvas.rect(0, 0, canvas.width, canvas.height);
  canvas.endDraw();

  return canvas;
}

String[] vertSrc = {"""
#version 330 core
uniform mat4 modelview;
uniform mat4 projection;
in vec4 position;
in vec4 texCoord;
out vec2 uv;
void main() {
  uv = texCoord.xy;
  gl_Position = projection * modelview * position;
}
"""};

String[] fragSrc = {"""
#version 330 core
in vec2 uv;
out vec4 fragColor;
void main() {
  fragColor = vec4( length(uv-0.5) < 0.25 ? vec2(0.) : uv, 0.0, 1.0 );
}
"""};

```

---

<div class="post-metadata">

### Author: ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)
#### Post date: [June 17, 2024, 11:06am UTC](https://discourse.processing.org/t/pimage-displays-well-but-exports-as-empty-file/44605/7 "2024-06-17T11:06:36Z")

</div>

Hello @TellAJoke,

I am getting different results today!  
I did get an empty file yesterday; maybe that is a message to not code on weekends!

I tested your code with _mousePressed_ in _draw()_ and as an event.  
Working this morning.

Use one or the other:

```auto
PImage img;

void draw() {
  background(0);

  if (mouseX < 1 || mouseY < 1) return;
  
  img = getPhenotype(mouseX, mouseY, shader);
  image(img, 0, 0);

  // This makes multiple saves
  //if (mousePressed) {
  // img.save("canvas.png");

  // PImage toExport = img.copy();
  // //toExport.updatePixels(); Did not need this!
  // toExport.save("img.png");
  // println(frameCount); //Monitor saves in console
  //}
}

// Saves once at end of draw()
void mousePressed()
  {
  img.save("canvas.png");

  PImage toExport = img.copy();
  //toExport.updatePixels(); Did not need this!
  toExport.save("img.png");
  println(frameCount); //Monitor saves in console
  }

```

The println() statements were useful for debugging.

I was able to monitor captures in real-time viewing the sketch window:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/8/a/8a2f24389c50769c2beb2e819550d5bf8173a7cb.png)

`:)`
