1

I am making a chess game in Python with PyGame using the python-chess library.

When I implement my program in PyGame the window only shows the empty board without the pieces. However, if I manually open the svg file that my code generates it shows correctly, with the pieces on the board. The problem is - when using blit to display the same image in PyGame I get an empty board.

To be clear, the issue is not a general 'loading SVG in PyGame' question. I am successfully displaying my SVG in this example. The question is a PyGame/python-chess question:
Why is PyGame loading the image that has the pieces in it as an empty board if it's the same file?

Code:

import pygame as pg
import chess
import chess.svg
import chess.pgn

WIDTH, HEIGHT = 900, 500
WINDOW = pg.display.set_mode((WIDTH,HEIGHT))
pg.display.set_caption('Opening mastery')
FPS = 60

board = chess.BaseBoard()

def get_board_img(brd):
    SVG = chess.svg.board(board=brd)
    f = open("image.svg", "w")
    f.write(SVG)
    f.close()
    image = ('image.svg')
    return image



def main():
    clock = pg.time.Clock()
    run = True
    while run:
        clock.tick(FPS)
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
        image = get_board_img(board)
        WINDOW.blit(pg.image.load(image),(0,0))
        pg.display.update()
        
           
    pg.quit()
if __name__ == '__main__':
    main()

This is the generated SVG file opened manually (it has the pieces)

This is the result (no pieces on the board)

Starbuck5
  • 1,649
  • 2
  • 7
  • 13
Rey Fit
  • 15
  • 4
  • Perhaps because your function writes to a file named `image.SVG`, but returns the filename `image.svg`? Those are not the same filename. – John Gordon Jan 04 '23 at 01:08
  • Good call but after editing both to be image.svg the same thing happens – Rey Fit Jan 04 '23 at 02:10
  • I'd suggest you save the board as a png image (or convert to a png) and load that instead. You may also be able to use pillow library to load the image and then use `pygame.image.frombytes` to load a PIL.Image – Matiiss Jan 04 '23 at 03:03
  • An SVG file is a text file (XML). If I run your code and open the "image.svg" file with a text editor, I can clearly see all the information about the figures in the file. So it is indeed an SVG problem and a bug in the Pygame SVG engine. So your code is correct and there is no answer to your question other than to create a Pygame issue report (https://github.com/pygame/pygame/issues) and use something other than Pygame to read the SVG. See [SVG rendering in PyGame](https://stackoverflow.com/questions/120584/svg-rendering-in-a-pygame-application-prior-to-pygame-2-0-pygame-did-not-suppo). – Rabbid76 Jan 05 '23 at 19:34

1 Answers1

3

It appears that pygame's SVG loading library (nanosvg) can't handle that SVG.

I found a workaround using cairosvg to convert the SVG to a PNG and then using pygame to load that.

I made a new get_board_image function that returns a surface directly

def get_board_img(brd):
    svg = chess.svg.board(board=brd)
    png_io = io.BytesIO()
    cairosvg.svg2png(bytestring=bytes(svg, "utf8"), write_to=png_io)
    png_io.seek(0)

    surf = pg.image.load(png_io, "png")
    return surf

It uses cairosvg to get the svg bytes into a png BytesIO object that pygame can load.

^ To get that snippet working in your code you need to add the imports for io and cairosvg (and install cairosvg) ofc, as well as changing your main loop a bit:

    while run:
        clock.tick(FPS)
        for event in pg.event.get():
            if event.type == pg.QUIT:
                run = False
        WINDOW.blit(get_board_img(board),(0,0))
        pg.display.update()
Starbuck5
  • 1,649
  • 2
  • 7
  • 13