I want to create an image in a wx Python application with the colour of the background.
[EDIT] On Windows this works perfectly:
[/EDIT]
but on linux my code gives a paler colour. What am I doing wrong?
[EDIT: more information]
The colour returned by self.GetBackgroundColour() is (225, 225, 225); the paler colour. The actual background colour is (212, 212, 212)
[\EDIT]
Here is an image taken using a different theme:
So based on Rolf's answer below it looks like an issue with Mate and not the theme
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Image')
sizer = wx.BoxSizer()
static_bitmap_A = wx.StaticBitmap(self, wx.ID_ANY)
bitmap = wx.Bitmap('any.png')
static_bitmap_A.SetBitmap(bitmap)
sizer.Add(static_bitmap_A, flag=wx.ALL, border=10)
image = wx.Image('any.png')
colour = self.GetBackgroundColour()
red, green, blue = colour[0], colour[1], colour[2]
#red, green, blue = 0, 0, 0
for row in range(image.GetSize()[0]):
for column in range(image.GetSize()[1]):
image.SetRGB(row, column, red, green, blue)
bitmap = wx.Bitmap(image)
static_bitmap_B = wx.StaticBitmap(self, wx.ID_ANY)
static_bitmap_B.SetBitmap(bitmap)
sizer.Add(static_bitmap_B, flag=wx.ALL, border=10)
self.SetSizerAndFit(sizer)
self.Show()
if __name__ == '__main__':
screen_app = wx.App()
main_frame = MainFrame()
screen_app.MainLoop()
Any image can be used in place of any.png
This is just to back up my original comments.
I can only assume that your issue is something to do with your Theme or other setup you have on your box, although I of course reserve the right to be horribly wrong.
This code, on Mint 19 (Ubuntu 18.04) Python 3.6 Wx 4.0.3 gtk2
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Image')
sizer = wx.BoxSizer()
sys_background = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
print("default colour ", sys_background)
static_bitmap_A = wx.StaticBitmap(self, wx.ID_ANY)
bitmap = wx.Bitmap('/home/rolf/any2.png')
static_bitmap_A.SetBitmap(bitmap)
sizer.Add(static_bitmap_A, flag=wx.ALL, border=10)
image = wx.Image('/home/rolf/any2.png')
#colour = self.GetBackgroundColour()
colour = sys_background
red, green, blue = colour[0], colour[1], colour[2]
print(red, green, blue)
for row in range(image.GetSize()[0]):# -1 ):
for column in range(image.GetSize()[1]):
image.SetRGB(row, column, red, green, blue)
bitmap = wx.Bitmap(image)
static_bitmap_B = wx.StaticBitmap(self, wx.ID_ANY,bitmap)
sizer.Add(static_bitmap_B, flag=wx.ALL, border=10)
self.SetSizerAndFit(sizer)
self.Show()
if __name__ == '__main__':
screen_app = wx.App()
main_frame = MainFrame()
screen_app.MainLoop()
Outputs (Theme Mint-X):
default colour (214, 214, 214, 255)
214 214 214
This continues to work properly, when changing the Theme, simply outputting different numbers for the colour values.
Theme Mint-Y
default colour (240, 240, 240, 255)
240 240 240
It works whether using colour = self.GetBackgroundColour() or colour = sys_background
Related
I'm using a PNG image as a background to a scatter plot, but the import somehow swaps red and blue. I can 'fix' it by swapping red and blue for each pixel, but that's not a proper solution. Does anyone know what goes wrong here?
See code below:
import sys
from PySide2.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout,
)
from PySide2.QtGui import (
QImage
)
import pyqtgraph as pg
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("RGB Issue")
self.setGeometry(100, 100, 600, 200)
# set up widgets
self.add_widgets()
# show widgets
self.show()
def add_widgets(self):
# create a plot window
plot = pg.plot()
# add an image
img = QImage('flowers.png')
# convert to a format imageToArray accepts
img = img.convertToFormat(QImage.Format_ARGB32_Premultiplied)
img_array = pg.imageToArray(img, copy=True)
# ==> uncomment next line to swap red and blue
# img_array = self.swap_red_and_blue(img_array)
img_item = pg.ImageItem(img_array)
# push image back so it ends up behind the spots in the plot
img_item.setZValue(-100)
plot.addItem(img_item)
# create a layout for our widget
layout = QVBoxLayout()
# our central widget
widget = QWidget()
# set widget layout
widget.setLayout(layout)
layout.addWidget(plot)
self.setCentralWidget(widget)
def swap_red_and_blue(self, img_array):
# swap red and blue for each pixel
for r in img_array:
for c in r:
c0old = c[0] # get red value
c1old = c[1] # get green value
c2old = c[2] # get blue value
c[0] = c2old # replace red with blue
c[1] = c1old # keep green
c[2] = c0old # replace blue with red
# c[3] = 255 # set alpha to opaque
return img_array
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
This is the original image:
This is the output I get:
I get the correct output if I call method swap_red_and_blue for each pixel in the code above.
I have been able to get black text on a white background and white text on a black background with this code. please any help to get black on yellow background and inverse
def color_inversion(self, frame):
if self.color == 1:
cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
if self.color == 2:
thresh, threading = cv2.threshold(frame, 150, 255, cv2.THRESH_BINARY)
image = cv2.cvtColor(threading, cv2.COLOR_RGB2GRAY)
maxIntensity = 255.0 # depends on dtype of image data
# Parameters for manipulating image data
phi = 1
theta = 1
newImage1 = (maxIntensity / phi) * (image / (maxIntensity / theta)) ** 1
image = array(newImage1, dtype=uint8)
cv2image = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, ` cv2.THRESH_BINARY, 115, 1)
if self.color == 3:
thresh, threading = cv2.threshold(frame, 150, 255, cv2.THRESH_BINARY)
image = cv2.cvtColor(threading, cv2.COLOR_RGB2GRAY)
maxIntensity = 255.0 # depends on dtype of image data
# Parameters for manipulating image data
phi = 1
theta = 1
newImage1 = (maxIntensity / phi) * (image / (maxIntensity / theta)) ** 1
image = array(newImage1, dtype=uint8)
run = cv2.adaptiveThreshold(image, 255, ` ` cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY, 115, 1)
cv2image = cv2.bitwise_not(run)
return cv2image
I want to create an image in a wx Python application with the colour of the background.
[EDIT] On Windows this works perfectly:
[/EDIT]
but on linux my code gives a paler colour. What am I doing wrong?
[EDIT: more information]
The colour returned by self.GetBackgroundColour() is (225, 225, 225); the paler colour. The actual background colour is (212, 212, 212)
[\EDIT]
Here is an image taken using a different theme:
So based on Rolf's answer below it looks like an issue with Mate and not the theme
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Image')
sizer = wx.BoxSizer()
static_bitmap_A = wx.StaticBitmap(self, wx.ID_ANY)
bitmap = wx.Bitmap('any.png')
static_bitmap_A.SetBitmap(bitmap)
sizer.Add(static_bitmap_A, flag=wx.ALL, border=10)
image = wx.Image('any.png')
colour = self.GetBackgroundColour()
red, green, blue = colour[0], colour[1], colour[2]
#red, green, blue = 0, 0, 0
for row in range(image.GetSize()[0]):
for column in range(image.GetSize()[1]):
image.SetRGB(row, column, red, green, blue)
bitmap = wx.Bitmap(image)
static_bitmap_B = wx.StaticBitmap(self, wx.ID_ANY)
static_bitmap_B.SetBitmap(bitmap)
sizer.Add(static_bitmap_B, flag=wx.ALL, border=10)
self.SetSizerAndFit(sizer)
self.Show()
if __name__ == '__main__':
screen_app = wx.App()
main_frame = MainFrame()
screen_app.MainLoop()
Any image can be used in place of any.png
This is just to back up my original comments.
I can only assume that your issue is something to do with your Theme or other setup you have on your box, although I of course reserve the right to be horribly wrong.
This code, on Mint 19 (Ubuntu 18.04) Python 3.6 Wx 4.0.3 gtk2
import wx
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'Image')
sizer = wx.BoxSizer()
sys_background = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)
print("default colour ", sys_background)
static_bitmap_A = wx.StaticBitmap(self, wx.ID_ANY)
bitmap = wx.Bitmap('/home/rolf/any2.png')
static_bitmap_A.SetBitmap(bitmap)
sizer.Add(static_bitmap_A, flag=wx.ALL, border=10)
image = wx.Image('/home/rolf/any2.png')
#colour = self.GetBackgroundColour()
colour = sys_background
red, green, blue = colour[0], colour[1], colour[2]
print(red, green, blue)
for row in range(image.GetSize()[0]):# -1 ):
for column in range(image.GetSize()[1]):
image.SetRGB(row, column, red, green, blue)
bitmap = wx.Bitmap(image)
static_bitmap_B = wx.StaticBitmap(self, wx.ID_ANY,bitmap)
sizer.Add(static_bitmap_B, flag=wx.ALL, border=10)
self.SetSizerAndFit(sizer)
self.Show()
if __name__ == '__main__':
screen_app = wx.App()
main_frame = MainFrame()
screen_app.MainLoop()
Outputs (Theme Mint-X):
default colour (214, 214, 214, 255)
214 214 214
This continues to work properly, when changing the Theme, simply outputting different numbers for the colour values.
Theme Mint-Y
default colour (240, 240, 240, 255)
240 240 240
It works whether using colour = self.GetBackgroundColour() or colour = sys_background
So I have been working on a game and for some odd reason down in the level1 function I thought if I had a while loop with leveltext1 = false then I could write the text onto the screen, and then wait 2 seconds and then make level1text = true and it would go away. I guess it didnt...
Code:
#!/usr/bin/python
import pygame
import time
pygame.init()
blue = (25,25,112)
black = (0,0,0)
red = (200,0,0)
bright_red = (255,0,0)
white = (255,255,255)
groundcolor = (139,69,19)
green = (80,80,80)
other_green = (110,110,110)
lives = 0
gameDisplay = pygame.display.set_mode((1336,768))
pygame.display.set_caption("TheAviGame")
direction = 'none'
clock = pygame.time.Clock()
img = pygame.image.load('guyy.bmp')
famousdude = pygame.image.load('kitten1.bmp')
kitten = pygame.image.load('macharacterbrah.bmp')
dorritosman = pygame.image.load('Doritos.bmp')
backround = pygame.image.load('backroundd.bmp')
playernormal = pygame.image.load('normalguy.bmp')
playerocket = pygame.image.load('rocketguyy.bmp')
rocketcat = pygame.image.load('jetpackcat.bmp')
mlglogo = pygame.image.load('mlg.bmp')
level1bg = pygame.image.load('level1background.bmp')
def mts(text, textcolor, x, y, fs):
font = pygame.font.Font(None,fs)
text = font.render(text, True, textcolor)
gameDisplay.blit(text, [x,y])
def button(x,y,w,h,ic,ac):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(gameDisplay, ac,(x,y,w,h))
if click[0] == 1:
gameloop()
else:
pygame.draw.rect(gameDisplay, ic,(x,y,w,h))
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
#print(event)
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(black)
button(450,450,250,70,green,other_green)
mts("Play", white, 540, 470, 50)
mts("THE AVI GAME", red, 380, 100, 100)
gameDisplay.blit(famousdude, (100,100))
gameDisplay.blit(kitten, (700,300))
gameDisplay.blit(dorritosman, (1000,400))
pygame.display.update()
clock.tick(15)
def gameloop():
imgx = 1000
imgy = 100
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
imgx += 10
gameDisplay.blit(backround, (30,30))
gameDisplay.blit(rocketcat, (imgx,imgy))
pygame.display.update()
clock.tick(15)
def level1():
imgx = 500
imgy = 500
leveltext = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
while not leveltext:
gameDisplay.blit(level1bg, (0,0))
mts("LEVEL 1:", red, 450, 220, 60)
mts('Controls: W or Up to move up.', white, 450, 300, 40)
mts('Controls: A or Left to move left.', white, 450, 340, 40)
mts('Controls: S or Down to move down.', white, 450, 390, 40)
mts('Controls: D or Right to move Right.', white, 450, 430, 40)
time.sleep(2)
leveltext = True
pygame.display.update()
level1()
From my understanding, when you blit text onto a surface it permanently becomes part of that surface. If you want the font to disappear, you could try blitting it onto a copy of that surface and then blit the altered surface to the display.
My previous attempt at asking this question was horrible and I had also made some progress, please bear with me, I did not intend to re-ask this so many times, and it is not my style.
Here is the final version: I am resizing a window that contains a DC Client painted bitmap and on the EVT_SIZE event, I am resizing it by re-scaling it (using scale, not rescale) and re-painting the image. The problem is it does not appear as though its respecting the aspect ratio even though I am calculating w/h for it. Also when it grows in height the image is distorted. Finally, when another window passes over it, the image goes white. Any ideas how to fix any of these issues? My window/image class is below:
class TransactionImage(wx.Window):
def __init__(self, parent, fname, name):
wx.Window.__init__(self, parent, name=name)
self.dc = wx.ClientDC(self)
self.load_image(fname)
cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER)
self.SetCursor(cursor)
self.Bind(wx.EVT_SIZE, self.resize_space)
def load_image(self, image):
self.image = wx.Image(image, wx.BITMAP_TYPE_JPEG)
(w, h) = self.image.GetSize()
self.image_ar = w/h
def resize_space(self, size):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
self.dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
# how can I 'refresh this area to make it 'fit'
def get_best_size(self):
(window_width, window_height) = self.GetSizeTuple()
new_height = window_width / self.image_ar
new_size = (window_width, new_height)
return new_size
Also, I am having trouble understanding how to properly use the Client DC. I want to refresh the window area before re-drawing the next image, because if i dont i get weird risiduals and it looks bad. In order to fix this I tried using dc.Clear which cleans the background off. However, doing so on every size call as i would need to causes the image to flash white a million times while im re-sizing. how can i avoid this?
EDIT -
In response to Umyal's comment response - here is a very simplified version of my application. Either way I class my window generator for the images the size handler re-scaling the images causes the image to flicker badly, creating an unappealing artifact. Also, when another frame passes over the application, the image display becomes white, as if been erased.
I was thinking as a way around this - I could implement the solution windows image viewer seems to have, which is the image is only rescaled and repainted when the user lets go of the edge of the frame when resizing it. Problem with that solution is that there is no clear way to detect when the user stops resizing the frame. (wxEVT_SIZE, wxEVT_SIZING)
Here is the simplified application code, you will need to find your own images and the bigger the better. The original image dimentions are 3872 x 2592
# this is required for 'real' math - derive the 'aspect ratio'
from __future__ import division
import wx
class TransactionImage(wx.Window):
def __init__(self, parent, fname, name):
wx.Window.__init__(self, parent, name=name)
self.load_image(fname)
cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER)
self.SetCursor(cursor)
self.Bind(wx.EVT_SIZE, self.resize_space)
self.Bind(wx.EVT_PAINT, self.on_paint)
def load_image(self, image):
self.image = wx.Image(image, wx.BITMAP_TYPE_JPEG)
(w, h) = self.image.GetSize()
self.image_ar = w/h
self.bitmap = wx.BitmapFromImage(self.image)
def resize_space(self, event):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
def on_paint(self, event):
self.dc = wx.PaintDC(self)
self.dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
def get_best_size(self):
(window_width, window_height) = self.GetSizeTuple()
new_height = window_width / self.image_ar
new_size = (window_width, new_height)
return new_size
class OriginalTransactionImage(wx.Window):
def __init__(self, parent, fname, name):
wx.Window.__init__(self, parent, name=name)
self.dc = wx.ClientDC(self)
self.load_image(fname)
cursor = wx.StockCursor(wx.CURSOR_MAGNIFIER)
self.SetCursor(cursor)
self.Bind(wx.EVT_SIZE, self.resize_space)
def load_image(self, image):
self.image = wx.Image(image, wx.BITMAP_TYPE_JPEG)
(w, h) = self.image.GetSize()
self.image_ar = w/h
def resize_space(self, size):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
self.dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
def get_best_size(self):
(window_width, window_height) = self.GetSizeTuple()
new_height = window_width / self.image_ar
new_size = (window_width, new_height)
return new_size
class ImageBrowser(wx.Frame):
def __init__(self, image1, image2, parent=None, id=wx.ID_ANY,
pos=wx.DefaultPosition, title='Image Browser'):
size = (1500, 800)
wx.Frame.__init__(self, parent, id, title, pos, size)
self.CentreOnScreen()
self.panel = wx.Panel(self, wx.ID_ANY)
self.panel.SetBackgroundColour(wx.Colour(191,197,229))
self.main_sizer = wx.BoxSizer(wx.VERTICAL)
self.image_panel = wx.Panel(self.panel, wx.ID_ANY, style=wx.SIMPLE_BORDER)
self.image_panel.SetBackgroundColour(wx.Colour(255, 255, 255))
self.image_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.image_panel.SetSizer(self.image_sizer)
self.load_image_sizer(image1, image2)
self.main_sizer.Add(self.image_panel, 1, wx.GROW|wx.ALIGN_CENTER|wx.ALL, 25)
self.panel.SetSizer(self.main_sizer)
def load_image_sizer(self, image1, image2):
#bitmap1 = OriginalTransactionImage(self.image_panel, image1, 'image1')
#bitmap2 = OriginalTransactionImage(self.image_panel, image2, 'image2')
bitmap1 = TransactionImage(self.image_panel, image1, 'image1')
bitmap2 = TransactionImage(self.image_panel, image2, 'image2')
self.image_sizer.Add(bitmap1, 1, wx.GROW|wx.ALIGN_LEFT|wx.ALL, 20)
self.image_sizer.Add(bitmap2, 1, wx.GROW|wx.ALIGN_RIGHT|wx.ALL, 20)
class IBApp(wx.App):
def OnInit(self):
img1 = "0_3126_image1.jpeg"
img2 = "0_3126_image2.jpeg"
ib = ImageBrowser(img1, img2)
ib.Show()
self.SetTopWindow(ib)
return True
app = IBApp(False, None)
app.MainLoop()
Do not keep a reference to client DC in your window instance(http://docs.wxwidgets.org/2.6/wx_wxclientdc.html) ,neither it is the proper way of drawing over window dc
instead bind to PAINT_EVENT and draw there, below i have shown the things you said add to your class
class TransactionImage(wx.Window):
def __init__(self, parent, fname, name):
self.Bind(wx.EVT_SIZE, self.resize_space)
self.Bind(wx.EVT_PAINT, self.onpaint)
def onpaint(self):
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bitmap, 0, 0, useMask=False)
def resize_space(self, size):
(w, h) = self.get_best_size()
self.s_image = self.image.Scale(w, h)
self.bitmap = wx.BitmapFromImage(self.s_image)
self.Refresh()