On 26/02/22 12:37 am, Eric Blake wrote:
On Fri, Feb 25, 2022 at 11:58:30AM +0000, Kshitij Suri wrote:
Currently screendump only supports PPM format, which is un-compressed and not
standard. Added a "format" parameter to qemu monitor screendump capabilites
to support PNG image capture using libpng. The param was added in QAPI schema
of screendump present in ui.json along with png_save() function which converts
pixman_image to PNG. HMP command equivalent was also modified to support the
feature.

Example usage:
{ "execute": "screendump", "arguments": { "filename": "/tmp/image",
"format":"png" } }

Resolves: 
https://urldefense.proofpoint.com/v2/url?u=https-3A__gitlab.com_qemu-2Dproject_qemu_-2D_issues_718&d=DwIBAg&c=s883GpUCOChKOHiocYtGcg&r=utjv19Ej9Fb0TB7_DX0o3faQ-OAm2ypPniPyqVSoj_w&m=N58ni_R8AQHe3XV2MX9aeKN2mCiEkpdyiqhV71sHDUEIuIk3P1HcXc-QfepnNaIE&s=CM400Sor3Oiio6iq3V_F9jFMCrn8UdbeKKXDnIh2QRw&e=

Signed-off-by: Kshitij Suri <kshitij.s...@nutanix.com>
---
+        .args_type  = "filename:F,device:s?,head:i?,format:f?",
+        .params     = "filename [device [head]] [format]",
+        .help       = "save screen from head 'head' of display device 'device'"
+                      "in specified format 'format' as image 'filename'."
+                      "Currently only 'png' and 'ppm' formats are supported.",
          .cmd        = hmp_screendump,
          .coroutine  = true,
      },
SRST
  ``screendump`` *filename*
-  Save screen into PPM image *filename*.
+  Save screen as an image *filename*.
Maybe:

as an image *filename*, with default format of PPM.

  ERST
{
diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c
index 8c384dc1b2..c300545f34 100644
--- a/monitor/hmp-cmds.c
+++ b/monitor/hmp-cmds.c
@@ -1677,9 +1677,15 @@ hmp_screendump(Monitor *mon, const QDict *qdict)
      const char *filename = qdict_get_str(qdict, "filename");
      const char *id = qdict_get_try_str(qdict, "device");
      int64_t head = qdict_get_try_int(qdict, "head", 0);
+    const char *input_format  = qdict_get_str(qdict, "format");
      Error *err = NULL;
+    ImageFormat format = IMAGE_FORMAT_PPM;
+    if (input_format != NULL && strcmp(input_format, "png") == 0) {
+        format = IMAGE_FORMAT_PNG;
+    }
Instead of open-coding the string-to-enum translation (which will be
hard to located if we expand to a third format down the road), you
should use qapi_enum_parse(&ImageFormat_lookup, ...).

+++ b/ui/console.c
@@ -37,6 +37,9 @@
  #include "exec/memory.h"
  #include "io/channel-file.h"
  #include "qom/object.h"
+#ifdef CONFIG_PNG
+#include <png.h>
+#endif
#define DEFAULT_BACKSCROLL 512
  #define CONSOLE_CURSOR_PERIOD 500
@@ -289,6 +292,87 @@ void graphic_hw_invalidate(QemuConsole *con)
      }
  }
+#ifdef CONFIG_PNG
+/**
+ * png_save: Take a screenshot as PNG
+ *
+ * Saves screendump as a PNG file
+ *
+ * Returns true for success or false for error.
+ *
+ * @fd: File descriptor for PNG file.
+ * @image: Image data in pixman format.
+ * @errp: Pointer to an error.
+ */
+static bool png_save(int fd, pixman_image_t *image, Error **errp)
+{
+    int width = pixman_image_get_width(image);
+    int height = pixman_image_get_height(image);
+    g_autofree png_struct *png_ptr = NULL;
+    g_autofree png_info *info_ptr = NULL;
+    g_autoptr(pixman_image_t) linebuf =
+                            qemu_pixman_linebuf_create(PIXMAN_a8r8g8b8, width);
+    uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf);
+    FILE *f = fdopen(fd, "wb");
+    int y;
+    if (!f) {
+        error_setg(errp, "Failed to create file from file descriptor");
error_setg_errno() might be nicer to use here, since fdopen() failure sets 
errno.

+        return false;
+    }
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
+                                           NULL, NULL);
Indentation looks off.

+    if (!png_ptr) {
+        error_setg(errp, "PNG creation failed. Unable to write struct");
+        free(f);
free() is the wrong function to call on FILE*.  You meant fclose().
Apologies for this, will be replaced in the upcoming patch.
+        return false;
+    }
+
+    info_ptr = png_create_info_struct(png_ptr);
+
+    if (!info_ptr) {
+        error_setg(errp, "PNG creation failed. Unable to write info");
+        free(f);
and again

+        png_destroy_write_struct(&png_ptr, &info_ptr);
+        return false;
+    }
+
+    png_init_io(png_ptr, f);
+
+    png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+                 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    png_write_info(png_ptr, info_ptr);
+
+    for (y = 0; y < height; ++y) {
+        qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
+        png_write_row(png_ptr, buf);
+    }
+    qemu_pixman_image_unref(linebuf);
+
+    png_write_end(png_ptr, NULL);
+
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    if (fclose(f) != 0) {
+        error_setg(errp, "PNG creation failed. Unable to close file");
Another spot for error_setg_errno
Thank you for your response! Will send the updated patch out soon.


Regards,

Kshitij



Reply via email to