On Tue, May 2, 2023 at 5:56 PM Peter Maydell <peter.mayd...@linaro.org>
wrote:

> When we take a PNG screenshot the ordering of the colour channels in
> the data is not correct, resulting in the image having weird
> colouring compared to the actual display.  (Specifically, on a
> little-endian host the blue and red channels are swapped; on
> big-endian everything is wrong.)
>
> This happens because the pixman idea of the pixel data and the libpng
> idea differ.  PIXMAN_a9r8g8b8 defines that pixels are 32-bit values,
> with A in bits 24-31, R in bits 16-23, G in bits 8-15 and B in bits
> 0-7.  This means that on little-endian systems the bytes in memory
> are
>    B G R A
> and on big-endian systems they are
>    A R G B
>
> libpng, on the other hand, thinks of pixels as being a series of
> values for each channel, so its format PNG_COLOR_TYPE_RGB_ALPHA
> always wants bytes in the order
>    R G B A
>
> This isn't the same as the pixman order for either big or little
> endian hosts.
>
> The alpha channel is also unnecessary bulk in the output PNG file,
> because there is no alpha information in a screenshot.
>
> To handle the endianness issue, we already define in ui/qemu-pixman.h
> various PIXMAN_BE_* and PIXMAN_LE_* values that give consistent
> byte-order pixel channel formats.  So we can use PIXMAN_BE_r8g8b8 and
> PNG_COLOR_TYPE_RGB, which both have an in-memory byte order of
>     R G B
> and 3 bytes per pixel.
>
> (PPM format screenshots get this right; they already use the
> PIXMAN_BE_r8g8b8 format.)
>
> Cc: qemu-sta...@nongnu.org
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1622
> Fixes: 9a0a119a382867 ("Added parameter to take screenshot with screendump
> as PNG")
> Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>
>

Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com>


> ---
> Disclaimer: I don't have a BE system that I have convenient
> graphics output from that I can use to test the screenshot
> format there.
> ---
>  ui/console.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/ui/console.c b/ui/console.c
> index 6e8a3cdc62d..e173731e205 100644
> --- a/ui/console.c
> +++ b/ui/console.c
> @@ -311,7 +311,7 @@ static bool png_save(int fd, pixman_image_t *image,
> Error **errp)
>      png_struct *png_ptr;
>      png_info *info_ptr;
>      g_autoptr(pixman_image_t) linebuf =
> -                            qemu_pixman_linebuf_create(PIXMAN_a8r8g8b8,
> width);
> +        qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
>      uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf);
>      FILE *f = fdopen(fd, "wb");
>      int y;
> @@ -341,7 +341,7 @@ static bool png_save(int fd, pixman_image_t *image,
> Error **errp)
>      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_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
>                   PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
>
>      png_write_info(png_ptr, info_ptr);
> --
> 2.34.1
>
>

Reply via email to