Alternate to pygame Text Rendering in python [duplicate] - python

We have a small web app that we want to convert into something native. Right now, it's got a lot of moving parts (the backend, the browser etc.) and we'd like to convert it into a single tight application. We decided to use PyGame to do this and it's been fine so far except for a font rendering issue.
The string I'd like to render is कोझिकोड. This, correctly rendered looks like .
The specific code points are \u0915 \u094b \u091d \u093f \u0915 \u094b and \u0921
Now, this looks fine in my editor and my browser but when I try to render it in PyGame, I get this . Basically, the vowel sign (\u093f ि) should have been on the left of the झ but it appears to its right (and to the left of the क) thereby messing it up completely. This doesn't happen in a browser or a text editor (with the same input string) so I'm guessing it a renderer problem in PyGame.
There is one crude fix which works only in this specific case which i s to put the ि (\u093f) before the झ (\u091d). In that case, it renders properly like so . This relies on me knowing something about the language and putting that logic into the code. I have to deal with multiple languages here so that's not really feasible.
I don't have much experience with unicode so I don't know how to approach this problem. Is there something I can do to fix this?
In case it matters, I'm using the freesans font which is there on Debian and which has the necessary glyphs to render this.
Update:
The code to actually render this is as follows
# -*- coding: utf-8 -*-
import time
import pygame
# Pygame setup and create root window
pygame.font.init()
screen = pygame.display.set_mode((320, 200))
empty = pygame.Surface((320, 200))
font_file = pygame.font.match_font("freesans") # Select and
font = pygame.font.Font(font_file, 30) # open the font
writing = font.render(u"कोिझकोड कोझिकोड", True, (0, 0, 0)) # Render text on a surface
screen.fill((255, 255, 255)) # Clear the background
screen.blit(writing, (10, 10)) # Blit the text surface on the background
pygame.display.flip() # Refresh the display
input() # Wait for input before quitting
This is what it looks like
The first word is rendered correctly but we've done it by inverting the vowel and the letter positions as I mentioned in the crude fix. The second is written properly but not rendered correctly.
Update 2:
In the absence of anything else, I've decided to try to render the string into an image using an external program and then blit this image onto the PyGame Surface. I tried imagemagick but it messes us in the same way as this. Gimp works fine and so I'm planning to use the batch mode to get my work done.

I think is a SDL_ttf problem (the underlying component which actually renders the text).
While my IDE correctly renders the string
The SDL_TTF program does not:
There is the code: https://gist.github.com/ilario-pierbattista/be6b967b05fa2f1eb322f35988a33ad0
I'm still looking for a solution

I had to finally resort to a really ugly but usable workaround for my own situation. I wrote a script-fu plugin which takes a filename and a piece of text as arguments. It then writes out the text and saves it a png file using gimp. My program then loads this up and blits the png directly onto the surface.

Related

How to properly import an SVG path to manim

I am working on a logo on Inkscape and I would like to import it to manim. The file does import properly with all the paths of the SVG but a weird thing is happening.
My code for running the file is this:
class U_letter(Scene):
def construct(self):
letter = SVGMobject("u_letter")
self.add(letter)
letter.set_color(GREEN)
The SVG format of the letter I am trying to add is available here.
It currently has two layers and when importing it this way it displays fine on manim but my problem is that I have to set the fill of the 'inner path'(i.e the inside of the letter) to match the background of the scene and I would like to avoid this.
I tried creating a single path out of the letter by using the difference functionality on Inkscape and that's where my problems started because the final image appears distorted as shown here.
I am however looking for something like this as my final solution. I should also point out that I have been experiencing this behavior with other letters I have tried so far, D and A letters to be exact.
Your help would be greatly appreciated
As of current date (June 3, 2020), There is no "proper" way to import a SVG object, as you see, you can you use SVGMObject and it will work most of the time, but as manim parses the path itself it ignores many things from the SVG specification in it's implementation, so you would have to fix it yourself or wait until it is fixed.

Python hide already printed text

I'm creating a simple two-player board game where each player must place pieces on their own boards. What I would like to do is by either:
opening a new terminal window (regardless which OS the program is run on) for both players so that the board is saved within a variable but the other player cannot scroll up to see where they placed their pieces.
clearing the current terminal completely so that neither player could scroll and see the other player's board. I am aware of the unix 'clear' command but it doesn't achieve the effect I'm after and doesn't work with all OS's (though this might be something that I'll have to sacrifice to get a working solution)
I have tried clearing the screen but haven't been able to completely remove all the text. I don't have a preference; whichever method is easier. Also, if it would be easier to use a different method that I haven't thought of, all other suggestions are welcome. Thanks in advance!
EDIT: Other solutions give the appearance that text has been cleared but a user could still scroll up and see the text that was cleared. I'd like a way to remove any way that a user could see this text.
EDIT 2: Please read the other answers and the comments as they provide a lot of information about the topic as a whole. In particular, thanks to #zondo.
Consider using a portable terminal handling library. They abstract away the system specifica of common tasks like erasing the "screen" (i.e. terminal), or placing output at a specific position on the "screen" (again, meaning the text terminal). However, to use such a library effectively, you often have to switch to its style of generating output on the screen instead of naively printing strings.
curses is one such library (based on the C library ncurses) and included in the Python standard library. To get started, be sure to have a look at the curses tutorial in the official Python documentation.
I'd personally just use this.
import os
os.system("cls" if os.name == "nt" else "clear") #"cls" for Windows, otherwise "clear"
I would recomend a simple ANSI escape code to move the cursor position, Cursor Escape Codes, to the start of the board everytime. There is also an ANSI escape code that completly clears the console though, so you can choose.
If you are on windows you must first import colorama a module that makes windows prompt be able to use the ANSI codes as such:
import colorama # OR: from colorama import init
colorama.init() # AND THEN: init()
So if your board has n rows, after the user input for their turn, you move the cursor UP n rows + however many were required for user input, so if you wrote Input row, col: ... then you would go UP n+1, etc...
A simple example:
numLines = 1
print("Hello world!")
print("\033[<{0}>A".format(numLines), "This came AFTER hello world line")
You may not like this, it's a bit higher level than a basic two player board game, but there is always using some sort of GUI.
I personally like tkinter myself.
You don't want the option of people scrolling up to see printed text, but you can't remove what has been printed, that's like asking a printer to remove ink off a page. It's going to stay there.
Research a GUI interface, and try and make the game in that. Otherwise, you could let me take a stab at creating a explanatory piece of code that shows you how to use tkinter. If you do, link me the game you have so I can understand what you want.

Using PIL (Python Image Library) to detect image on screen

I am trying to understand how I can use PIL in Python 2.7 to search the whole screen for a certain image and click on it. I've been searching around and haven't been able to find a solution. I want to create a small GUI with one button in the middle of it that when clicked will search the entire screen for a predefined image. Once the image is found the program will then click in the centre of it and end. In short the program will detect if an image is present on the users screen and click it.
I did find an interesting bit on Sikuli, but that doesn't help me because it's unable to export to an .exe.
The image that the program will look for will most likely be in the same place each time it searches, but I didn't want to hard-code the location as it has the potential to move and I don't want that being an issue later on.
What I need is the code method I would use to search for the image on screen and send back the cords to a variable.
Image explanation/example:
Reference image of rifle:
PIL is the wrong tool for this job. Instead you should look into openCV (open source computer vision), which has fantastic python bindings. Here is a link to an example (in C but should be easy to redo with the python bindings) that does what you are looking for, but even allows the image to be rotated, scaled, etc.
http://docs.opencv.org/doc/tutorials/features2d/feature_homography/feature_homography.html
http://docs.opencv.org/doc/tutorials/features2d/detection_of_planar_objects/detection_of_planar_objects.html
Edit:
I assume you are using windows, as your example image looks like window. In this case you can use:
from PIL import ImageGrab
pil_img = ImageGrab.grab()
opencv_img = numpy.array(pil_img)
then use opencv to process the image to find sub image you are looking for.
If you want to do this cross platform, then you will need to use wxWidgets to do the screengrab: https://stackoverflow.com/a/10089645/455532
Even I wanted to do the same but using different module - pyautogui. I finally found the solution for my problem and I am sure this solution will also help you.
You have to just go to this webpage and read the locate function topic completely
and you'll be able to solve your problem.
I recommend you give a look on PyAutoGUI, a well documented library to control mouse and keyboard, also can locate imagens on screen, find the position, move the mouse to any location and clicks on location, also can simulate drag and drop, type on input fields, give double clicks and much more.

How to accept text input from a pygame GUI

I am working on a RPG game using Python and Pygame, and am trying to make a two-part GUI, including a lower part that is like the basic command line, and a top part that will show all graphical "action."
What I need to find out is a way to include both in a pygame window, instead of using a pygame window and terminal window. As well, are there any Pygame GUI toolkits that would be appropriate for this use?
Thanks All!
May I suggest using ezText instead?
It's a cool way to add text inupt bars to pygame. I used it before my self, and It's really easy to use.
http://www.pygame.org/project-EzText-920-.html
(feel free to leave a comment if you want help using it, although everything you need to know is in the example.py that comes with it)
Take a look here (http://wiki.python.org/moin/PythonGameLibraries) for a whole list of ToolKits for both Pygame and Pyglet. Albow (http://www.cosc.canterbury.ac.nz/greg.ewing/python/Albow/) has worked well for me in the past.
The easiest way to accomplish what you're talking about would be to make two Surfaces, one for each part of the interface, and then constantly update them in separate modules to finally blit them every frame. That way your main module can be simplified to something like:
import action_gui
import cl_gui
import pygame
pygame.init()
MAIN_SURF = pygame.display.set_mode((x, y))
pygame.display.set_caption('My Game')
while (True):
action_surf = action_gui.update()
cl_surf = cl_gui.update()
MAIN_SURF.blit(action_surf, my_position_1)
MAIN_SURF.blit(cl_surf, my_position_2)
Best of luck.

wxPython ,Change the background colour of a StyledTextCtrl

I tried (but nothing happens)
self.txt.SetBackgroundColour ((255,0,0))
As said in the title I'm trying to change the background colour StyledTextCtrl. Does anyone know a method that could be used? I've checked the API docs but I couldn't seem to find one, http://wxpython.org/docs/api/wx.stc.StyledTextCtrl-class.html
(by background colour, I mean the whole writing area, of course)
Does anyone know a way I could do this?
EDIT:
The background doesn't change in the following code
import wx
import wx.stc
app = wx.App(redirect=True)
top = wx.Frame(None, title="StyledTXTCtrl", size=(300,200))
txt=wx.stc.StyledTextCtrl(top)
txt.SetBackgroundColour((255,255,0))
txt.Refresh()
top.Show()
app.MainLoop()
My first reaction was to call txt.Refresh() because I had a similar experience using wx.TextCtrl where the background colour did not update and the Refresh() call forced a redraw. However, it seems that approach was incorrect.
After reviewing the StyledTextCtrl API, it seems like SetBackground() is not the function you want. My understanding is that because STCs can have multiple styles in the same box, the individual text styles take precedence over the STC's settings.
After some research I found the StyleSetBackground() function. This modifies the default style such that the background will be red, effectively setting the background to red. You need to call it like this:
txt.StyleSetBackground(wx.stc.STC_STYLE_DEFAULT, (255,0,0))
Just remember, if you use multiple styles you may need to make invoke this method for each one.
---EDIT---
I forgot to check my code code by entering some text. It turns out that if all you do is call SyleSetBackground() like I suggest above, when you enter text the background of the entered text is still white, not the expected red.
A bit more research and I've discoved this is easily fixed by calling the following code after setting the background colour:
txt.StyleClearAll()
My guess is that when you create the StyledTextCtrl, it sets the text style equal to wx.stc.STC_STYLE_DEFAULT. So far so good. However, after this point we change the value of the default style (by making the background red) so now the text style and the default style are different. Therefore, we need to call StyleClearAll() to reset ALL STYLES back to the default style (which now has a red background).
this works on my computer just fine
self.txt.SetBackgroundColour((255,0,0))
what is your OS?

Categories