diff mbox

[PATCH/RFC,7/7] Add PNG screendump

Message ID 1331557893-30806-8-git-send-email-marcandre.lureau@redhat.com
State New
Headers show

Commit Message

Marc-André Lureau March 12, 2012, 1:11 p.m. UTC
Dump an image in PNG format if the URI ends with ".png" and PNG
support is enabled.
---
 hw/vga.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 74 insertions(+), 1 deletions(-)

Comments

Daniel P. Berrangé March 12, 2012, 5:05 p.m. UTC | #1
On Mon, Mar 12, 2012 at 02:11:33PM +0100, Marc-André Lureau wrote:
> Dump an image in PNG format if the URI ends with ".png" and PNG
> support is enabled.
> ---
>  hw/vga.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 74 insertions(+), 1 deletions(-)
> 
> diff --git a/hw/vga.c b/hw/vga.c
> index 9f7ca89..0210cde 100644
> --- a/hw/vga.c
> +++ b/hw/vga.c
> @@ -32,6 +32,13 @@
>  #include "xen.h"
>  #include "qemu_socket.h"
>  
> +#ifdef CONFIG_PNG
> +/* The following define is needed by pngconf.h. Otherwise it won't compile,
> +   because setjmp.h was already included by qemu-common.h. */
> +#define PNG_SKIP_SETJMP_CHECK
> +#include <png.h>
> +#endif

[snip]

I'd be inclined to just switch over to use gdk-pixbuf for saving
images. It copes with a wide array of formats, and is a natrual
fit now that we're using GLib.  NB, gdk-pixbuf is distributed and
built separate from GDK/GTK, so this wouldn't create a hard dep
on GTK - you could still build with just the gdk-pixbuf support.

While allowing gdk-pixbuf to guess format based off the file
name is fine, I'd suggest we should add an explicit format argument
to the 'screendump' command. If omitted, the format would be
guessed from filename if possible.

Regards,
Daniel
diff mbox

Patch

diff --git a/hw/vga.c b/hw/vga.c
index 9f7ca89..0210cde 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -32,6 +32,13 @@ 
 #include "xen.h"
 #include "qemu_socket.h"
 
+#ifdef CONFIG_PNG
+/* The following define is needed by pngconf.h. Otherwise it won't compile,
+   because setjmp.h was already included by qemu-common.h. */
+#define PNG_SKIP_SETJMP_CHECK
+#include <png.h>
+#endif
+
 //#define DEBUG_VGA
 //#define DEBUG_VGA_MEM
 //#define DEBUG_VGA_REG
@@ -2422,6 +2429,39 @@  QEMUFile *qemu_fopen_uri(const char *uri, const char *mode)
     return f;
 }
 
+#ifdef CONFIG_PNG
+static void *vga_png_malloc(png_structp png_ptr, png_size_t size)
+{
+    return g_malloc(size);
+}
+
+static void vga_png_free(png_structp png_ptr, png_voidp ptr)
+{
+    g_free(ptr);
+}
+
+static void vga_png_write_data(png_structp png_ptr, png_bytep data,
+                               png_size_t length)
+{
+    QEMUFile *f = png_get_io_ptr(png_ptr);
+
+    qemu_put_buffer(f, (uint8_t*)data, length);
+}
+
+static void vga_png_flush_data(png_structp png_ptr)
+{
+}
+
+static int png_line_handler(void *opaque, uint8_t *line, size_t length)
+{
+    png_structp png_ptr = opaque;
+
+    png_write_row(png_ptr, line);
+
+    return length;
+}
+#endif
+
 static int ppm_line_handler(void *opaque, uint8_t *line, size_t length)
 {
     QEMUFile *f = opaque;
@@ -2482,7 +2522,39 @@  int ppm_save(const char *uri, struct DisplaySurface *ds)
     f = qemu_fopen_uri(uri, "wb");
     g_return_val_if_fail(f != NULL, -1);
 
-    {
+    if (g_str_has_suffix(uri, ".png")) {
+#ifdef CONFIG_PNG
+        png_structp png_ptr;
+        png_infop info_ptr;
+
+        png_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
+                                            NULL, NULL, NULL,
+                                            NULL, vga_png_malloc,
+                                            vga_png_free);
+        if (png_ptr == NULL) {
+            goto out;
+        }
+
+        info_ptr = png_create_info_struct(png_ptr);
+        if (info_ptr == NULL) {
+            png_destroy_write_struct(&png_ptr, NULL);
+            goto out;
+        }
+
+        png_set_write_fn(png_ptr, (void *)f,
+                         vga_png_write_data, vga_png_flush_data);
+        png_set_IHDR(png_ptr, info_ptr, ds->width, ds->height,
+                     8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+                     PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+        png_write_info(png_ptr, info_ptr);
+        screen_dump_lines(ds, png_line_handler, png_ptr);
+        png_write_end(png_ptr, NULL);
+        png_destroy_write_struct(&png_ptr, &info_ptr);
+#else
+        DPRINTF("PNG support is disabled");
+        goto out;
+#endif
+    } else {
         gchar *header;
         header = g_strdup_printf("P6\n%d %d\n%d\n", ds->width, ds->height, 255);
         qemu_put_buffer(f, (uint8_t*)header, strlen(header));
@@ -2491,6 +2563,7 @@  int ppm_save(const char *uri, struct DisplaySurface *ds)
     }
 
     ret = 0;
+out:
     qemu_fclose(f);
     return ret;
 }