Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] Maps with legend do not save properly as png or tiff files #757

Closed
baharmon opened this issue Jul 1, 2020 · 3 comments
Closed

[Bug] Maps with legend do not save properly as png or tiff files #757

baharmon opened this issue Jul 1, 2020 · 3 comments
Labels
bug Something isn't working GUI wxGUI related windows Microsoft Windows specific
Milestone

Comments

@baharmon
Copy link
Contributor

baharmon commented Jul 1, 2020

Describe the bug
On GRASS 7.8.3 on Windows 10 maps with a legend do not save properly as png or tiff files with the Save display to file dialog in the GUI or with a Cairo monitor using a Python script. Maps are saved as pngs with transparent cells except for the legend. Without a legend maps save properly. This is the case for both raster and vector legends. Maps, however, do save properly with m.printws.

To Reproduce

  1. Start GRASS 7.8.3 in the ncspm_basic_grass7 location
  2. add elevation@PERMANENT to the map display
  3. Add a legend for elevation raster with d.legend
  4. Save a png of the elevation raster with a legend using Save display to file
  5. Open the saved png

Expected behavior
Should save a png file with the map and legend.

Screenshots

Elevation map with legend from GRASS 7.7 Elevation map with legend from GRASS 7.8.3
elevation_legend_g77 elevation_legend

System description (please complete the following information):

  • Operating System: Windows 10
  • GRASS GIS version: 7.8.3
@baharmon baharmon added the bug Something isn't working label Jul 1, 2020
@neteler neteler added GUI wxGUI related windows Microsoft Windows specific labels Jul 1, 2020
@neteler neteler added this to the 7.8.4 milestone Jul 1, 2020
@tmszi
Copy link
Member

tmszi commented Jul 7, 2020

It works properly with a newer version of wxPython, tested with 4.1.0 msw (phoenix) wxWidgets 3.1.4.

Simple test script: overlay.py (save imgs below in the same directory as your script overlay.py). After run check result.png image file.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os

from PIL import Image

import wx
import wx.adv


dirname = os.path.dirname(__file__)

BG_MAP = os.path.join(dirname, 'map.png')
MAP_LEGEND = os.path.join(dirname, 'map_legend.png')
RESULT = os.path.join(dirname, 'result.png')


def PilImageToWxImage(pilImage, copyAlpha=True):
    """Convert PIL image to wx.Image

    Based on http://wiki.wxpython.org/WorkingWithImages
    """

    hasAlpha = pilImage.mode[-1] == 'A'
    if copyAlpha and hasAlpha:  # Make sure there is an alpha layer copy.
        wxImage = wx.Image(*pilImage.size)
        pilImageCopyRGBA = pilImage.copy()
        pilImageCopyRGB = pilImageCopyRGBA.convert('RGB')    # RGBA --> RGB
        fn = getattr(
            pilImageCopyRGB,
            "tobytes",
            getattr(
                pilImageCopyRGB,
                "tostring",
            ),
        )

        pilImageRgbData = fn()
        wxImage.SetData(pilImageRgbData)
        fn = getattr(
            pilImageCopyRGBA,
            "tobytes",
            getattr(
                pilImageCopyRGBA,
                "tostring",
            ),
        )
        # Create layer and insert alpha values.
        wxImage.SetAlpha(fn()[3::4])

    else:    # The resulting image will not have alpha.
        wxImage = wx.Image(*pilImage.size)
        pilImageCopy = pilImage.copy()
        # Discard any alpha from the PIL image.
        pilImageCopyRGB = pilImageCopy.convert('RGB')
        fn = getattr(
            pilImageCopyRGB,
            "tobytes",
            getattr(
                pilImageCopyRGB,
                "tostring",
            ),
        )
        pilImageRgbData = fn()
        wxImage.SetData(pilImageRgbData)

    return wxImage


def draw(pdc, coords, drawid, img):
    if drawid != 99:
        bg = wx.TRANSPARENT_BRUSH
    else:
        bg = wx.Brush(wx.WHITE)

    pdc.SetBackground(bg)

    bitmap = wx.Bitmap(img)
    w, h = bitmap.GetSize()
    pdc.DrawBitmap(
        bitmap, coords[0],
        coords[1],
        False,
    )  # draw the composite map
    pdc.SetIdBounds(drawid, wx.Rect(coords[0], coords[1], w, h))


def main():

    app = wx.App()

    pdc = wx.adv.PseudoDC()
    bg_map = wx.Image(BG_MAP, wx.BITMAP_TYPE_ANY)
    ibuffer = wx.Bitmap(
        max(1, bg_map.GetWidth()),
        max(1, bg_map.GetHeight()),
    )
    draw(pdc, (0, 0), 99, img=bg_map)

    legend_img = Image.open(MAP_LEGEND)
    imageBox = legend_img.getbbox()
    cropped = legend_img.crop(imageBox)
    legend = PilImageToWxImage(cropped)
    draw(pdc, (58, 324), 100, img=legend)

    dc = wx.BufferedDC(None, ibuffer)
    dc.Clear()
    pdc.DrawToDC(dc)

    ibuffer.SaveFile(RESULT, wx.BITMAP_TYPE_PNG)

    app.MainLoop()


if __name__ == '__main__':
    main()

Map (save as map.png file):
map

Map legend (save as map_legend.png file):
map_legend

@neteler
Copy link
Member

neteler commented Aug 11, 2020

What is the state of this report?

@petrasovaa
Copy link
Contributor

Thanks @tmszi for the analysis, it looks like the problem is resolved with newer wx version. Feel free to reopen if that is not the case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working GUI wxGUI related windows Microsoft Windows specific
Projects
None yet
Development

No branches or pull requests

4 participants