How to change the window size in Panda3D? - panda3d

A Panda3D program opens with a certain window size. I cannot find any call in GraphicsWindow to set or change the window size.
How do I change the window size?

You can change the initial window size in your Config.prc file, OR you can prepend the following code in your main python file:
from panda3d.core import loadPrcFileData
loadPrcFileData('', 'win-size 1024 768')
If you want to change the window size at runtime the following code should do the trick:
w, h = 1024, 768
props = WindowProperties()
props.setSize(w, h)
self.win.requestProperties(props)
Hope it helps.

Related

Why does this code slow down? Graphics.py?

I have some code that reads a small BMP (128x96) file and puts the RGB values into a list.
I then run a nested loop and read the RGB values in reverse from the list and draw them on the screen.
It starts quite quickly and draws the first 20 lines in a second, but progressively slows down to such an extent I've never seen it finish. It only a small 128x96 image.
I feel it's the calls to the graphics.py library, buy why, or is it something else?
I'm running this on a raspberry pi, if that's of use. Python 3.4.2
If your interested in trying you can find the supporting files here https://drive.google.com/open?id=1yM9Vn1Nugnu79l1UNShamEAGd2VWF3T4
(It's the graphics.py library I'm using and the tiny bmp file, also the actual file in question called SlowDownWhy.py)
import math
import sys
from graphics import *
from PIL import Image
# Initialise Vars for Image width n height
iw=0
ih=0
img=Image.open("ani1.bmp","r") # Open Image
iw, ih = img.size # Set image width n height
ch = int(1000/ih) # Cube height set
cw = ch # Cube width set
win = GraphWin("My Window", iw*cw, ih*ch)
win.setBackground(color_rgb(128,128,128))
#Transfer Bitmap RGB vales to csv list - 'RGBlist'
pix_val = list(img.getdata())
RGBlist = [x for sets in pix_val for x in sets]
noe = (iw * ih * 3)-3
x = iw
y = ih
for vy in list(range(ih)):
y = y-1
x = iw
for vx in list(range(iw)):
x = x-1
r=RGBlist[noe]
g=RGBlist[noe+1]
b=RGBlist[noe+2]
noe=noe-3
cx=x*cw
cy=y*ch
aPoint = Rectangle(Point(cx,cy), Point(cx+cw,cy+ch))
aPoint.setFill(color_rgb(r,g,b))
aPoint.draw(win)
It should create a window no bigger than 1000 pixels in height and start drawing the picture from the bottom right to the top left, line by line. but slows down progressively.
Ignoring the invalid syntax, this is simply because of the way graphics.py is programmed: It is not designed to handle this many objects put onto the screen. (It uses tkinter in the back-end, which will slow down with 128*96=12,288 objects). For rendering images, you should either directly integrate them or use another library, as example pygame.
To integrate it into the graphics.py program, there is the Image-class, which you overwrote with the PIL.Image-library (this is the reason why you never do import *). Look here: Importing custom images into graphics.py

Is it possible to resize an image by its bytes rather than width and height?

I wanted to reduce an image to a smaller size for easy sharing and faster uploading.
But I realized if I just reduce the size by its h&w, it doesn't really do the trick because a large image file may have a smaller h&w, and small image file may have a large h&w, so reduce image size by reduce its height & weight may not always shrink the size the way I wanted.
So now I have got the byte size using this:
import os
os.stat('myImage.jpg').st_size
Is it possible to reduce the image size by reducing its byte? And remain its ratio?
Here's a function I wrote with PIL. It does some iterative resizing and jpeg compression of an image to then look at the resulting file size and compare it to a target value, guessing the next best width/height combination from the size deviation ratio (basically some sort of a P controller).
It makes use of io.BytesIO which does all the resizing stuff in memory, so there's really only one read and one write access to files on the disk. Also, with this bruteforce approach, you can alter the target file format to let's say PNG, and it would work out of the box.
from PIL import Image
import os
import io
def limit_img_size(img_filename, img_target_filename, target_filesize, tolerance=5):
img = img_orig = Image.open(img_filename)
aspect = img.size[0] / img.size[1]
while True:
with io.BytesIO() as buffer:
img.save(buffer, format="JPEG")
data = buffer.getvalue()
filesize = len(data)
size_deviation = filesize / target_filesize
print("size: {}; factor: {:.3f}".format(filesize, size_deviation))
if size_deviation <= (100 + tolerance) / 100:
# filesize fits
with open(img_target_filename, "wb") as f:
f.write(data)
break
else:
# filesize not good enough => adapt width and height
# use sqrt of deviation since applied both in width and height
new_width = img.size[0] / size_deviation**0.5
new_height = new_width / aspect
# resize from img_orig to not lose quality
img = img_orig.resize((int(new_width), int(new_height)))
limit_img_size(
"test.jpg", # input file
"test_with_limited_size.jpg", # target file
50000, # bytes
tolerance = 5 # percent of what the file may be bigger than target_filesize
)
EDIT:
With "in memory" I meant that when it saves the img to buffer in the loop, it saves it to a BytesIO object, which is not a file on the disk but in memory. And from that object I can then determine the resulting file size (which is just the length of that data buffer) without actually saving it to a file. In the end maybe that's just how you'd expect it to work, but I've seen too many codes that waste performance on saving files on disk due to a lack of knowledge about Python's io.BytesIO.
Only the final result will be saved to a file - and that's ofc where you want. Try using an absoulte filename for img_target_filename.
it happened that a friend of mine needed to resize/rescale a personal image and it was required that the image to be at most 40KB. I wrote the following code to downscale/rescale the image considering the size on disk. I assume 40KB = 40000Bytes which is not exact but it can come handy
from skimage.io import imread, imshow
from skimage.transform import rescale, resize, downscale_local_mean
from skimage.io import imsave
import matplotlib.pyplot as plt
import os
import numpy as np
img = imread('original.jpg')
target_size = 40000
size = os.path.getsize('original.jpg')
factor = 0.9
while(size>=40000):
image_rescaled = rescale(img, factor, anti_aliasing=False)
imsave('new.jpg', image_rescaled)
print('factor {} image of size {}'.format(factor,size))
factor = factor - 0.05
size = os.path.getsize('new.jpg')
end_size = os.path.getsize('new.jpg')
print(end_size)
Hope it helps!!!!
You can follow me on GitHub as LeninGF

How do I get the actual geometry attributes of a window created using tkinter and python 3.6.0?

I create a window which is 1500 pixels wide x 900 pixels tall with an x offset of 220 pixels and a y offset of 120 pixels. Immediately after the creation I try to access the width and height of the window and I get values that don't correspond to the actual window.
This is the printed output.
Right after Creation
size_string 1500x900+220+120
current geometry 1x1+220+120
root_width, root_reqwidth 1 200
root_height, root_reqheight 1 200
winfo_x, winfo_y 0 0
This is the code.
from tkinter import *
def callback():
print ("Not Yet Defined")
root = Tk()
root.title("Manage My Money")
# This segment sets the size of the window and the offsets
win_height_pixels=900
win_width_pixels=1500
win_x_offset_pixels=220
win_y_offset_pixels=120
size_string=str(win_width_pixels)+"x"+str(win_height_pixels)+"+"+str(win_x_offset_pixels)+"+"+str(win_y_offset_pixels)
root.geometry(size_string)
# This prints out the attributes of the window
print("Right after Creation")
print ("size_string",size_string)
current_geom=root.geometry()
print ("current geometry", current_geom)
root_width=root.winfo_width()
root_reqwidth=root.winfo_reqwidth()
print ("root_width, root_reqwidth", root_width, root_reqwidth)
root_height=root.winfo_height()
root_reqheight=root.winfo_reqheight()
print ("root_height, root_reqheight", root_height, root_reqheight)
winfo_x=root.winfo_x()
winfo_y=root.winfo_y()
print("winfo_x, winfo_y", winfo_x, winfo_y)
If you call winfo_width() or winfo_reqwidth() before the window appears on the screen, you will not get the actual size of the window. You must first make the window appear.

pygame.transform.scale not working on a font surface

I am trying to make a function in a pygame program for python 3. The function basically makes the multiple-line process of blitting words onto the screen simpler by making it one function, MakeWord(). It has some parameters to adjust size, font, position, etc. Instead of making the font based on normal font sizes, I wanted it based on pixel sizes so I did pygame.transfom.flip() on a font surface and it did not work. Can someone find the problem please?
def MakeWord(Phrase, Font, Color, Pos, Size):
FontType = pygame.font.SysFont(Font, 400) #400 because the size will be changed anyways
FontSurf = FontType.render(Phrase, True, Color)
pygame.transform.scale(FontSurf, Size) #Does not work
FontRect = FontSurf.get_rect()
FontRect.topleft = Pos
Display.blit(FontSurf, FontRect)
return FontRect #For FontRect.collidepoint(pygame.mouse.get_pos) used later
pygame.transform.scale returns a new Surface object. Try to assign it to FontSurf:
FontSurf = pygame.transform.scale(FontSurf, Size)

Specify Width and Height of Plot

I have a panel containing three plots. How can I use par to specify the width and height of the main panel so it is always at a fixed size?
You do that in the device, e.g.
x11(width=4, height=6)
and similarly for the file-based ones
pdf("/tmp/foo.pdf", width=4, height=6)
You can read the physical size via par("cin") etc but not set it.
Neither solution works in Jupyter notebooks. Here is a general approach that works in any environment:
options(repr.plot.width=6, repr.plot.height=4)
Just keep the following function handy:
set_plot_dimensions <- function(width_choice, height_choice) {
options(repr.plot.width=width_choice, repr.plot.height=height_choice)
}
EXAMPLE
Data
x <- c(37.50,46.79,48.30,46.04,43.40,39.25,38.49,49.51,40.38,36.98,40.00,38.49,37.74,47.92,44.53,44.91,44.91,40.00,41.51,47.92,36.98,43.40)
Call function with dimensions, and draw plot:
set_plot_dimensions(6, 4)
show_distribution(x, 'test vector')
set_plot_dimensions(16, 4)
show_distribution(x, 'test vector')
I usually set this at the start of my session with windows.options:
windows.options(width=10, height=10)
# plot away
plot(...)
If you need to reset to "factory settings":
dev.off()
windows.options(reset=TRUE)
# more plotting
plot(...)

Resources