I am trying to copy a file and generate progress in a progress bar while it happens. I had to split the copying down to separate threads because tkinter wouldn't spawn the gui otherwise. All works fine with one thread, but as soon as a start another, the GUI doesn't update, it's just blank. Here's the code that matters:
def move_bar():
global stop
text.set(f'Moving {to_move[last_sep + 1:]}...')
while stop:
if mque.empty():
continue
else:
a = mque.get()
prog.set(a)
pgs.update()
else:
stop = 1
#copy_bar()
def copy_bar():
text.set(f'Copying {to_move[last_sep + 1:]}...')
while stop:
if cque.empty():
continue
else:
a = cque.get()
prog.set(a)
pgs.update()
else:
root.destroy()
def copyfile(src, dst):
global stop
pyway = 1024 * 1024 # Found this number in the shutil module
length = size if size < pyway else pyway
p = 0
with threading.Lock(): # Will be in it's own thread, lock till done
with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
with memoryview(bytearray(length)) as mv:
while True:
# r (int) contains the size of the chunck written
r = fsrc.readinto(mv)
if not r:
break
elif r < length:
with mv[:r] as smv:
fdst.write(smv)
else:
fdst.write(mv)
cque.put(p)
p += r
stop = 0
def movefile(src, dst):
global stop
pyway = 1024 * 1024 # Found this number in the shutil module
p = 0
with threading.Lock(): # Will be in it's own thread, lock till done
length = size if size < pyway else pyway
with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
with memoryview(bytearray(length)) as mv:
while True:
# r (int) contains the size of the chunck written
r = fsrc.readinto(mv)
if not r:
break
elif r < length:
with mv[:r] as smv:
fdst.write(smv)
else:
fdst.write(mv)
mque.put(p)
p += r
stop = 0
os.remove(src)
#to_move = sys.argv[1] # file dragged onto script
to_move = 'D:\\00.mkv'
size = os.stat(to_move).st_size
last_sep = to_move.rfind('\\')
# Create the GUI
root = T.Tk()
text = T.StringVar()
prog = T.IntVar()
lbl = T.Label(root, textvariable=text, font=(None, 13))
lbl.grid()
pgs = t.Progressbar(root, orient='horizontal', length=150, mode='determinate',
maximum=size, variable=prog)
pgs.grid(row=1)
s = time.time()
root.after(250, move_bar)
drives_dict = get_drive_name(get_drive_letters())
height = get_pixel_height(to_move)
# If I ever change my encodes so that DVDs height is more or less than
# 480, I'll have to change the next line:
if height == 480:
path1 = drives_dict['Back-Ups'] + 'My Movies\\DVD Rips\\'
path2 = drives_dict['Movies'] + 'DVD Rips\\'
else:
path1 = drives_dict['Back-Ups'] + 'My Movies\\Blu-ray Rips\\'
path2 = drives_dict['Movies'] + 'Blu-ray Rips\\'
move_to = path1 + to_move[last_sep + 1:]
copy_to = path2 + to_move[last_sep + 1:]
# Multiple threads because tkinter doesn't want to generate when the main
# thread is tied up:
t1 = threading.Thread(target=movefile, args=(to_move, move_to))
t1.start()
#t2 = threading.Thread(target=copyfile, args=(move_to, copy_to))
#t2.start()
root.mainloop()
Anyone have an idea why two threads mess up tkinter? Have I done something wrong?
Related
I've got a weather display for a Pi which uses pygame to display the data
The issue I have is when the internet dies for any reason there is no update and the display shows blank data
What I'd like to do is if there is no update then it keeps the previous data on the screen
is this possible?
This is an example of the code that displays the data
if forecastData.status == forecast.STATUS_OK:
ren = font.render("Solar Radiation: {} W/m2".format(forecastData.solar_radiation), 1, pg.Color('black'), pg.Color(185,208,240))
else:
ren = font.render("Solar Radiation: ", 1, pg.Color('black'), pg.Color(185,208,240))
screen.blit(ren, (5*HRES//1600, 430*VRES//900-ren.get_height()//2))
When there is no update this displays Solar Radiation: only - I'd like this to use the previous data - ie DONT update this section of the display
It seems like what you should do is check the status before updating self.data in your Forecast class:
#Now make it available to outside world.
if data.status == STATUS_OK:
self.lock.acquire()
self.data = data
self.lock.release()
Can't be sure as it's not possible to run any of your code samples.
Here is a minimal example that uses a thread to simulate data retrieval with the occasional error.
import random
import threading
import time
import pygame
class ForecastThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.start() # starts on instantiation!
def retrieve_data(self):
global data
# make request to forecast service and parse response
response = random.randint(1, 5)
if response == 1:
# Request failed
data = """(○o◌!*^##!#"""
else: # success
data = random.choice(("Cloudy", "Rainy", "Stormy", "Sunny", "Windy"))
def run(self):
while True:
if not running: # exit thread if main loop exits
return
else:
self.retrieve_data()
time.sleep(1) # sleep for a second
WIDTH = 480
HEIGHT = 240
FPS = 30
random.seed(98765432)
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# grab the first installed font
sys_font = pygame.font.SysFont(pygame.font.get_fonts()[0], 100)
data = "" # create globals before thread
running = True
forecaster_thread = ForecastThread() # note: thread is auto-starting
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYUP:
if event.key == pygame.K_ESCAPE:
running = False
# update title bar
pygame.display.set_caption(f"Forecaster FPS: {clock.get_fps():.1f}")
# fill background to clear
window.fill(pygame.Color("lightsteelblue2"))
# create image
image = sys_font.render(data, True, pygame.Color("black"))
window.blit(image, (50, 50)) # blit close to centre
# show surface
pygame.display.update()
# limit frames
clock.tick(FPS)
pygame.quit()
Running this code will initially display Cloudy then change to the gibberish data indicating a failed request.
If you change the retrieve_data() function to not update data on failure, then no gibberish will be displayed.
def retrieve_data(self):
global data
# make request to forecast service and parse response
response = random.randint(1, 5)
if response == 1:
# Request failed
print("Failed Request") # log the error
else: # success
data = random.choice(("Cloudy", "Rainy", "Stormy", "Sunny", "Windy"))
"import random" I have tried your solution so many ways but it always fails Does this help?... this is the full code to collect the forecast
import json
import urllib.request
import urllib.error
import time
from datetime import datetime
from datetime import timedelta
import pdb
import threading
import pygame as pg
import logging
import os.path
import socket
FORECAST_URL = "https://swd.weatherflow.com/swd/rest/better_forecast?api_key=20c70eae-e62f-4d3b-b3a4-8586e90f3ac8&station_id=44303&lat=53.440&lon=-2.105"
TIMEOUT = 15
STATUS_TIMEOUT = "Timeout"
STATUS_OK = "OK"
def nullis0hook(d):
"""This is a hook for the JSON decoder, replacing null with 0."""
for k in d.keys():
if d[k]==None:
d[k]=0
return d
class ForecastData:
def __init__(self):
self.status = STATUS_OK
self.conditions=""
self.iconnow = ""
self.updateTime="946684800"
self.tempnow=0
self.templow=30
self.temphigh=-10
self.sea_level_pressure=0
self.station_pressure=0
self.pressure_trend=""
self.relative_humidity=0
self.wind_avg=0
self.wind_direction_cardinal=""
self.angle=0
self.wind_gust=0
self.solar_radiation=0
self.uv=0
self.feels_like=0
self.dew_point=0
self.wet_bulb_temperature=""
self.delta_t=0
self.air_density=0
self.lightning_strike_last_distance="0"
self.lightning1=""
self.lightning_strike_last_epoch="946684800"
self.precip_accum_local_yesterday="0"
self.precip_accum_local_day="0"
self.condday=[""]*6
self.icon=[""]*6
self.iconday_filename = [os.path.join("images",os.path.join("forecast_icons","--_"))]*6
self.iconday = [pg.image.load(os.path.join("images",os.path.join("forecast_icons","--_1.bmp"))).convert()]*6
self.thighday=[0]*6
self.tlowday=[0]*6
self.sunriseday=[""]*6
self.sunsetday=[""]*6
self.precprday=[0]*6
self.precpiconday=[""]*6
self.preciptypeday=[""]*6
self.conditionshour=[""]*9
self.iconhour=[""]*9
self.precipprhour=[""]*9
self.preciptypehour=[""]*9
self.feelslikehour=[0]*9
self.conditionshour=[""]*9
self.iconhour=[""]*9
self.precipprhour=[""]*9
self.preciptypehour=[""]*9
self.feelslikehour=[0]*9
self.airtemphour=[0]*9
self.windavghour=[0]*9
self.forecast_icon_filename = os.path.join("images",os.path.join("weather_icons","--_.bmp"))
self.forecast_icon = pg.image.load(self.forecast_icon_filename).convert()
self.kia = pg.image.load(os.path.join("images",os.path.join("weather_icons","kia.png"))).convert()
#The Forecast class retrieves the weatherflow.com forecast and extracts relevant forecast data.
#Note: pygame display must be initialized before constructing a Forecast object
class ForeCastHour:
def __init__(self):
self.conditions = [""]*6
self.icon = ["--_"]*6
self.precipr = [""]*6
self.precip_type = [""]*6
self.feels_like = [""]*6
class Forecast:
def __init__(self):
self.data = ForecastData()
self.lock = threading.Lock()
self.max_wind_gust=0
self.templow=30
self.temphigh=-10
self.updateTime = ""
def getData(self):
"""Get most recently retrieved consistent set of data."""
self.lock.acquire()
data = self.data
self.lock.release()
return data
def midnightReset(self):
"""Reset any values that require resetting at midnight"""
self.lock.acquire()
self.data.wind_gust=0
self.lock.release()
def update(self):
"""Update the forecast data"""
data = ForecastData()
try:
req = urllib.request.Request(FORECAST_URL)
with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
raw = response.read()
forecast_json = json.loads(raw, object_hook=nullis0hook)
data.status = STATUS_OK
self.updateTime = forecast_json["current_conditions"]["time"]
data.updateTime = time.strftime("%H:%M:%S", time.localtime(self.updateTime))
data.conditions = forecast_json["current_conditions"]["conditions"]
iconnow = forecast_json["current_conditions"]["icon"]
if iconnow == "null":
iconnow = "--_" #icon replacement
if iconnow == "":
iconnow = "--_" #icon replacement
data.iconnow_filename = os.path.join("images",os.path.join("weather_icons",iconnow+".bmp"))
if os.path.exists(data.iconnow_filename):
data.iconnow = pg.image.load(data.iconnow_filename).convert()
else:
logging.warning("Weather icon file {} not found.".format(data.iconnow_filename))
data.tempnow = forecast_json["current_conditions"]["air_temperature"]
if data.tempnow < self.templow:
self.templow = data.tempnow
if data.tempnow > self.temphigh:
self.temphigh = data.tempnow
data.templow = self.templow
data.temphigh = self.temphigh
data.sea_level_pressure = forecast_json["current_conditions"]["sea_level_pressure"]
data.station_pressure = forecast_json["current_conditions"]["station_pressure"]
data.pressure_trend = forecast_json["current_conditions"]["pressure_trend"]
data.relative_humidity = forecast_json["current_conditions"]["relative_humidity"]
data.wind_avg = forecast_json["current_conditions"]["wind_avg"]* 2.23694 #Convert mps to mph
data.wind_gust = forecast_json["current_conditions"]["wind_gust"] * 2.23694 #Convert mps to mph
data.angle = forecast_json["current_conditions"]["wind_direction"]
if data.angle <= 180:
data.angle = data.angle + 180
else:
data.angle = data.angle - 180
data.wind_direction_cardinal = forecast_json["current_conditions"]["wind_direction_cardinal"]
data.solar_radiation = forecast_json["current_conditions"]["solar_radiation"]
data.uv = forecast_json["current_conditions"]["uv"]
data.feels_like = forecast_json["current_conditions"]["feels_like"]
lightning_strike_last_distance = forecast_json["current_conditions"].get("lightning_strike_last_distance", 0)
lightning1 = lightning_strike_last_distance*0.621371 #Convert kph to mph
data.lightning_strike_last_distance = "{0:.1f} miles away ".format(lightning1)
lightning_strike_last_epoch = forecast_json["current_conditions"].get("lightning_strike_last_epoch")
data.lightning_strike_last_epoch = time.strftime("%d %b", time.localtime(lightning_strike_last_epoch))
data.precip_accum_local_yesterday = forecast_json["current_conditions"]["precip_accum_local_yesterday"]
data.precip_accum_local_day = forecast_json["current_conditions"]["precip_accum_local_day"]
for day in range(6):
data.sunriseday[day] = forecast_json["forecast"]["daily"][day]["sunrise"]
data.sunriseday[day] = time.strftime("%H:%M:%S", time.localtime(data.sunriseday[day]))
data.sunsetday[day] = forecast_json["forecast"]["daily"][day]["sunset"]
data.sunsetday[day] = time.strftime("%H:%M:%S", time.localtime(data.sunsetday[day]))
data.condday[day] = forecast_json["forecast"]["daily"][day]["conditions"]
icon = forecast_json["forecast"]["daily"][day]["icon"]
data.iconday_filename[day] = os.path.join("images",os.path.join("forecast_icons",icon+"1.bmp"))
if os.path.exists(data.iconday_filename[day]):
iconimage = pg.image.load(data.iconday_filename[day]).convert()
data.iconday[day] = iconimage
else:
logging.warning("Forecast icon file {} not found.".format(data.iconday_filename[day]))
data.thighday[day] = forecast_json["forecast"]["daily"][day]["air_temp_high"]
data.tlowday[day] = forecast_json["forecast"]["daily"][day]["air_temp_low"]
data.precprday[day] = forecast_json["forecast"]["daily"][day]["precip_probability"]
if data.precprday[day] != 0:
data.precpiconday[day] = forecast_json["forecast"]["daily"][day]["precip_icon"]
data.preciptypeday[day] = forecast_json["forecast"]["daily"][day]["precip_type"]
data.forecast_icon_filename = os.path.join("images",os.path.join("weather_icons",iconnow+".bmp"))
if os.path.exists(data.forecast_icon_filename):
data.forecast_icon = pg.image.load(data.forecast_icon_filename).convert()
else:
logging.warning("Forecast icon file {} not found.".format(data.forecast_icon_filename))
for hours in range(9):
ps = forecast_json["forecast"]["hourly"][hours]["conditions"]
if ps == "Wintry Mix Possible":
ps = "Winty-P"
if ps == "Wintry Mix Likely":
ps = "Winty-L"
if ps == "Rain Likely":
ps = "Rain-L"
if ps == "Rain Possible":
ps ="Rain-P"
if ps == "Snow Possible":
ps = "Snow-P"
if ps == "Thunderstorms Likely":
ps = "ThundrL"
if ps == "Thunderstorms Possible":
ps = "ThundrP"
if ps == "Partly Cloudy":
ps = "Clouds"
if ps == "Very Light Rain":
ps = "drizzle"
data.conditionshour[hours] = "{}".format(ps)
data.iconhour[hours] = forecast_json["forecast"]["hourly"][hours]["icon"]
pp = forecast_json["forecast"]["hourly"][hours]["precip_probability"]
data.precipprhour[hours] = "{}%".format(pp)
if pp == 0:
data.preciptypehour[hours] = "0"
else:
data.preciptypehour[hours] = forecast_json["forecast"]["hourly"][hours]["precip_type"]
data.feelslikehour[hours] = "{} C".format(forecast_json["forecast"]["hourly"][hours]["feels_like"])
data.airtemphour[hours] = forecast_json["forecast"]["hourly"][hours]["air_temperature"]
data.windavghour[hours] = forecast_json["forecast"]["hourly"][hours]["wind_avg"]*0.621371 #Convert kph to mph
#datetime object containing current date and time
now = datetime.now()
data.updateTime = now.strftime("%H:%M:%S")
self.updateTime = now
except (socket.timeout, socket.gaierror, urllib.error.URLError, json.decoder.JSONDecodeError, KeyError):
logging.warning("Error retrieving forecast data")
#declare timeout only after timeout period
if datetime.now() - self.updateTime > timedelta(seconds=TIMEOUT):
data.status = STATUS_TIMEOUT
data.updateTime = self.data.updateTime #Use old update time value
else: #If timeout period has not elapsed yet, use previous data
logging.info("Not timing out yet")
self.data = self.data #Use old value
if datetime.now() - self.updateTime > timedelta(seconds=TIMEOUT):
data.status = STATUS_TIMEOUT
else: #If timeout period has not elapsed yet, use previous data
logging.info("Not timing out yet")
data = self.data
#Now make it available to outside world.
self.lock.acquire()
self.data = data
self.lock.release()
And this is what works when there is internet, but when the internet goes off it doesn't use the old data
'''THIS IS THE FORECAST SECTION THAT WORKS WHEN THERE IS INTENET AND FORECAST UPDATES
BUT WHEN THERE IS NO UPDATE IT JUST DISPLAYS THE TEXT AND DOES NOT USE THE OLD DATA VALUE'''
if forecastData.status == forecast.STATUS_OK:
ren = font.render("battery voltage : " + "{} V".format(forecastData.battery), 1, pg.Color('white'), pg.Color(162, 160, 160))
else:
ren = font.render("", 1, pg.Color('white'), pg.Color(162, 160, 160))
screen.blit(ren, (700*HRES//1600, VRES//60))
if forecastData.status == forecast.STATUS_OK:
ren = font.render("Conditions: {} ".format(forecastData.conditions), 1, pg.Color('black'), pg.Color(185,208,240))
else:
ren = font.render("Conditions: ", 1, pg.Color('black'), pg.Color(185,208,240))
screen.blit(ren, (5*HRES//1600, 70*VRES//900-ren.get_height()//2))
'''THIS IS THE ERROR MESSAGE I GET LOGGED'''
2021-04-15 13:28:41,057 - root - INFO - Updating forecast.
2021-04-15 13:28:41,087 - root - WARNING - Error retrieving forecast data
2021-04-15 13:29:11,049 - root - WARNING - Previous every-minute thread still running. Not relaunching.
2021-04-15 13:29:26,602 - root - INFO - t key pressed. Toggle fullscreen.
2021-04-15 13:29:41,085 - root - WARNING - Previous every-minute thread still running. Not relaunching.
2021-04-15 13:30:11,089 - root - WARNING - Previous every-minute thread still running. Not relaunching.
'''THIS IS THE FUNCTION THAT THE ERROR REFERS TO'''
def everyMinuteThreadFunction():
"""This thread function executes once every minute."""
global initialWeatherUpdateReceived, everyMinuteThreadRunning
everyMinuteThreadRunning = True
assert(forecastObj)
checkMidnightRollOver()
logging.info("Updating forecast.")
forecastObj.update()
forecastData = forecastObj.getData()
if forecastData.status == forecast.STATUS_OK:
logging.info("Forecast data: {}".format(vars(forecastData)))
#The first time we pass here is a good time to kick off the five minute task. We now have our first
#forecast evice data available
if not initialWeatherUpdateReceived:
#program a periodic timer used to kick off the everyFiveMinutesThreadFunction.
pg.time.set_timer(EVERY_FIVE_MINUTES_THREAD_FUNCTION_EVENT, 5*60000)
#Kick off the task now, for the initial interval.
t = threading.Thread(target=everyFiveMinutesThreadFunction, args=())
t.daemon = True
t.start()
updateGauge()
initialWeatherUpdateReceived = True
everyMinuteThreadRunning = False
I am using the Pillow library of Python to read in image files. How can I compress and decompress using Huffman encoding? Here is an instruction:
You have been given a set of example images and your goal is to compress them as much as possible without losing any perceptible information –upon decompression they should appear identical to the original images. Images are essentially stored as a series of points of color, where each point is represented as a combination of red, green, and blue (rgb). Each component of the rgb value ranges between 0-255, so for example: (100, 0, 200) would represent a shade of purple. Using a fixed-length encoding, each component of the rgb value requires 8 bits to encode (28= 256) meaning that the entire rgb value requires 24 bits to encode. You could use a compression algorithm like Huffman encoding to reduce the number of bits needed for more common values and thereby reduce the total number of bits needed to encode your image.
# For my current code I just read the image, get all the rgb and build the tree
from PIL import Image
import sys, string
import copy
codes = {}
def sortFreq(freqs):
letters = freqs.keys()
tuples = []
for let in letters:
tuples.append (freqs[let],let)
tuples.sort()
return tuples
def buildTree(tuples):
while len (tuples) > 1:
leastTwo = tuple (tuples[0:2]) # get the 2 to combine
theRest = tuples[2:] # all the others
combFreq = leastTwo[0][0] + leastTwo[1][0] # the branch points freq
tuples = theRest + [(combFreq, leastTwo)] # add branch point to the end
tuples.sort() # sort it into place
return tuples[0] # Return the single tree inside the list
def trimTree(tree):
# Trim the freq counters off, leaving just the letters
p = tree[1] # ignore freq count in [0]
if type (p) == type (""):
return p # if just a leaf, return it
else:
return (trimTree (p[0]), trimTree (p[1]) # trim left then right and recombine
def assignCodes(node, pat=''):
global codes
if type (node) == type (""):
codes[node] = pat # A leaf. Set its code
else:
assignCodes(node[0], pat+"0") # Branch point. Do the left branch
assignCodes(node[1], pat+"1") # then do the right branch.
dictionary = {}
table = {}
image = Image.open('fall.bmp')
#image.show()
width, height = image.size
px = image.load()
totalpixel = width*height
print ("Total pixel: "+ str(totalpixel))
for x in range (width):
for y in range (height):
# print (px[x, y])
for i in range (3):
if dictionary.get(str(px[x, y][i])) is None:
dictionary[str(px[x, y][i])] = 1
else:
dictionary[str(px[x, y][i])] = dictionary[str(px[x, y][i])] +1
table = copy.deepcopy(dictionary)
#combination = len(dictionary)
#for value in table:
# table[value] = table[value] / (totalpixel * combination) * 100
#print(table)
print(dictionary)
sortdic = sortFreq(dictionary)
tree = buildTree(sortdic)
trim = trimTree(tree)
print(trim)
assignCodes(trim)
print(codes)
The class HuffmanCoding takes complete path of the text file to be compressed as parameter. (as its data members store data specific to the input file).
The compress() function returns the path of the output compressed file.
The function decompress() requires path of the file to be decompressed. (and decompress() is to be called from the same object created for compression, so as to get code mapping from its data members)
import heapq
import os
class HeapNode:
def __init__(self, char, freq):
self.char = char
self.freq = freq
self.left = None
self.right = None
def __cmp__(self, other):
if(other == None):
return -1
if(not isinstance(other, HeapNode)):
return -1
return self.freq > other.freq
class HuffmanCoding:
def __init__(self, path):
self.path = path
self.heap = []
self.codes = {}
self.reverse_mapping = {}
# functions for compression:
def make_frequency_dict(self, text):
frequency = {}
for character in text:
if not character in frequency:
frequency[character] = 0
frequency[character] += 1
return frequency
def make_heap(self, frequency):
for key in frequency:
node = HeapNode(key, frequency[key])
heapq.heappush(self.heap, node)
def merge_nodes(self):
while(len(self.heap)>1):
node1 = heapq.heappop(self.heap)
node2 = heapq.heappop(self.heap)
merged = HeapNode(None, node1.freq + node2.freq)
merged.left = node1
merged.right = node2
heapq.heappush(self.heap, merged)
def make_codes_helper(self, root, current_code):
if(root == None):
return
if(root.char != None):
self.codes[root.char] = current_code
self.reverse_mapping[current_code] = root.char
return
self.make_codes_helper(root.left, current_code + "0")
self.make_codes_helper(root.right, current_code + "1")
def make_codes(self):
root = heapq.heappop(self.heap)
current_code = ""
self.make_codes_helper(root, current_code)
def get_encoded_text(self, text):
encoded_text = ""
for character in text:
encoded_text += self.codes[character]
return encoded_text
def pad_encoded_text(self, encoded_text):
extra_padding = 8 - len(encoded_text) % 8
for i in range(extra_padding):
encoded_text += "0"
padded_info = "{0:08b}".format(extra_padding)
encoded_text = padded_info + encoded_text
return encoded_text
def get_byte_array(self, padded_encoded_text):
if(len(padded_encoded_text) % 8 != 0):
print("Encoded text not padded properly")
exit(0)
b = bytearray()
for i in range(0, len(padded_encoded_text), 8):
byte = padded_encoded_text[i:i+8]
b.append(int(byte, 2))
return b
def compress(self):
filename, file_extension = os.path.splitext(self.path)
output_path = filename + ".bin"
with open(self.path, 'r+') as file, open(output_path, 'wb') as output:
text = file.read()
text = text.rstrip()
frequency = self.make_frequency_dict(text)
self.make_heap(frequency)
self.merge_nodes()
self.make_codes()
encoded_text = self.get_encoded_text(text)
padded_encoded_text = self.pad_encoded_text(encoded_text)
b = self.get_byte_array(padded_encoded_text)
output.write(bytes(b))
print("Compressed")
return output_path
""" functions for decompression: """
def remove_padding(self, padded_encoded_text):
padded_info = padded_encoded_text[:8]
extra_padding = int(padded_info, 2)
padded_encoded_text = padded_encoded_text[8:]
encoded_text = padded_encoded_text[:-1*extra_padding]
return encoded_text
def decode_text(self, encoded_text):
current_code = ""
decoded_text = ""
for bit in encoded_text:
current_code += bit
if(current_code in self.reverse_mapping):
character = self.reverse_mapping[current_code]
decoded_text += character
current_code = ""
return decoded_text
def decompress(self, input_path):
filename, file_extension = os.path.splitext(self.path)
output_path = filename + "_decompressed" + ".txt"
with open(input_path, 'rb') as file, open(output_path, 'w') as output:
bit_string = ""
byte = file.read(1)
while(byte != ""):
byte = ord(byte)
bits = bin(byte)[2:].rjust(8, '0')
bit_string += bits
byte = file.read(1)
encoded_text = self.remove_padding(bit_string)
decompressed_text = self.decode_text(encoded_text)
output.write(decompressed_text)
print("Decompressed")
return output_path
Running the program:
Save the above code, in a file huffman.py.
Create a sample text file. Or download a sample file from sample.txt (right click, save as)
Save the code below, in the same directory as the above code, and Run this python code (edit the path variable below before running. initialize it to text file path)
UseHuffman.py
from huffman import HuffmanCoding
#input file path
path = "/home/ubuntu/Downloads/sample.txt"
h = HuffmanCoding(path)
output_path = h.compress()
h.decompress(output_path)
The compressed .bin file and the decompressed file are both saved in the same directory as of the input file.
Result
On running on the above linked sample text file:
Initial Size: 715.3 kB
Compressed file Size: 394.0 kB
Plus, the decompressed file comes out to be exactly the same as the original file, without any data loss.
And that is all for Huffman Coding implementation, with compression and decompression. This was fun to code.
The above program requires the decompression function to be run using the same object that created the compression file (because the code mapping is stored in its data members). We can also make the compression and decompression function run independently, if somehow, during compression we store the mapping info also in the compressed file (in the beginning). Then, during decompression, we will first read the mapping info from the file, then use that mapping info to decompress the rest file.
So I'm making a game in python and when I shoot my fly object it explodes, but then after it explodes no more objects come down. I need to know how to fix this so that objects will keep coming down for me to shoot and destroy. Here's my code:
SPEED = 3
#set initial location of image
image_x = random.randrange(0, 480)
image_y = -50
image_y = image_y + SPEED
if image_y > 640:
image_x = random.randrange(0, 480)
image_y = -25
def __init__(self, x = 40, y = 40, speed = 2, odds_change = 200):
""" Initialize the Fly object. """
super(Fly, self).__init__( image = Fly.image,
y = y, x = random.randrange(0, 480),
dy = speed,
dx = speed)
self.bottom = 0
self.odds_change = odds_change
self.time_til_drop = 500
def update(self):
""" Determine if direction needs to be reversed."""
if self.left < 0 or self.right > games.screen.width:
self.dx = -self.dx
elif random.randrange(self.odds_change) == 0:
self.dx = -self.dx
self.check_drop()
def check_drop(self):
""" Decrease countdown or drop fly and reset countdown. """
if self.time_til_drop > 0:
self.time_til_drop -= 1
else:
self.time_til_drop = 500
new_fly = Fly(x = self.x)
games.screen.add(new_fly)
#set buffer to approx 30% of fly height regardless of fly speed
self.time_til_drop = int(new_fly.height * 1000 / Fly.SPEED) + 1000
def die(self):
"""Destroy Fly."""
#If fly is destroyed, then continue playing
self.destroy()
You're not actually using a class, you're just writing functions.
trying to search within a .thumbdata3 file for thumbnail images. This was someone else's sample code, but I am getting an error
"str does not support the buffer interface using .find"
"""extract files from Android thumbdata3 file"""
f=open('thumbdata3.dat','rb')
tdata = f.read()
f.close()
ss = '\xff\xd8'
se = '\xff\xd9'
count = 0
start = 0
while True:
x1 = tdata.find(ss,start)
if x1 < 0:
break
x2 = tdata.find(se,x1)
jpg = tdata[x1:x2+1]
count += 1
fname = 'extracted%d03.jpg' % (count)
fw = open(fname,'wb')
fw.write(jpg)
fw.close()
start = x2+2
ok, turned out to be very simple.
just add b in front of the data I am trying to match
so
ss = '\xff\xd8'
se = '\xff\xd9'
becomes
ss = b'\xff\xd8'
se = b'\xff\xd9'
It's all right.
With Python 3.x like python-3.6.2
Rename .thumbdata3-1763508120 file to thumbdata3.dat
Rename .thumbdata3--1967290299 file to thumbdata4.dat
enter code here
"""extract files from Android thumbdata3 file"""
f=open('thumbdata3.dat','rb')
tdata = f.read()
f.close()
ss = b'\xff\xd8'
se = b'\xff\xd9'
count = 0
start = 0
while True:
x1 = tdata.find(ss,start)
if x1 < 0:
break
x2 = tdata.find(se,x1)
jpg = tdata[x1:x2+1]
count += 1
fname = 'extracted%d03.jpg' % (count)
fw = open(fname,'wb')
fw.write(jpg)
fw.close()
start = x2+2
enter code here
"""extract files from Android thumbdata4 file"""
f=open('thumbdata4.dat','rb')
tdata = f.read()
f.close()
ss = b'\xff\xd8'
se = b'\xff\xd9'
count = 0
start = 0
while True:
x1 = tdata.find(ss,start)
if x1 < 0:
break
x2 = tdata.find(se,x1)
jpg = tdata[x1:x2+1]
count += 1
fname = 'extracted%d04.jpg' % (count)
fw = open(fname,'wb')
fw.write(jpg)
fw.close()
start = x2+2
I was unsure whether to post the full code or not, but here's what I have:
from tkinter import *
from random import randint
HEIGHT = 500
WIDTH = 800
MID_X = WIDTH/2
MID_Y = HEIGHT/2
SHIP_R = 15
SHIP_SPD = 10
bub_id = list()
bub_r = list()
bub_speed = list()
MIN_BUB_R = 10
MAX_BUB_R = 30
MAX_BUB_SPD = 6
GAP = 100
window = Tk()
window.title('Bubble Blaster')
c = Canvas(window, width=WIDTH, height=HEIGHT, bg='darkblue')
c.pack()
ship_id = c.create_polygon(5, 5, 5, 25, 30, 15, fill='red')
ship_id2 = c.create_oval(0, 0, 30, 30, outline='red')
c.move(ship_id, MID_X, MID_Y)
c.move(ship_id2, MID_X, MID_Y)
def move_ship(event):
fixed = True
while fixed == True:
ship_x, ship_y = event.x, event.y
c.move(ship_id, ship_x, ship_y)
c.move(ship_id2, ship_x, ship_y)
sleep(0.01)
def create_bubble():
x = WIDTH + GAP
y = randint(0, HEIGHT)
r = randint(MIN_BUB_R, MAX_BUB_R)
id1 = c.create_oval(x-r, y-r, x+r, y+r, outline='white')
bub_id.append(id1)
bub_r.append(r)
bub_speed.append(randint(1, MAX_BUB_SPD))
def move_bubbles():
for i in range(len(bub_id)):
c.move(bub_id[i], -bub_speed[i], 0)
def get_coords(id_num):
pos = c.coords(id_num)
x = (pos[0] + pos[2])/2
y = (pos[1] + pos[3])/2
return x, y
def del_bubble(i):
del bub_r[i]
del bub_speed[i]
c.delete(bub_id[i])
del bub_id[i]
def clean_up_bubs():
for i in range(len(bub_id)-1, -1, -1):
x, y = get_coords(bub_id[i])
if x < -GAP:
del_bubble(i)
from math import sqrt
def distance(id1, id2):
x1, y1 = get_coords(id1)
x2, y2 = get_coords(id2)
return sqrt((x2-x1)**2 + (y2-y1)**2)
def collision():
points = 0
for bub in range(len(bub_id)-1, -1, -1):
if distance(ship_id2, bub_id[bub]) < (SHIP_R+bub_r[bub]):
points += (bub_r[bub] + bub_speed[bub])
del_bubble(bub)
return points
c.create_text(50, 30, text='TIME', fill='white')
c.create_text(150, 30, text='SCORE', fill='white')
time_text = c.create_text(50, 50, fill='white')
score_text = c.create_text (150, 50, fill='white')
def show_score(score):
c.itemconfig(score_text, text=str(score))
def show_time(time_left):
c.itemconfig(time_text, text=str(time_left))
from time import sleep, time
BUB_CHANCE = 20
TIME_LIMIT = 30
BONUS_SCORE = 1000
# MAIN GAME LOOP
c.bind("<B1_Motion>", move_ship)
score = 0
bonus = 0
end = time() + TIME_LIMIT
while time() < end:
if randint(1, BUB_CHANCE) == 1:
create_bubble()
move_bubbles()
move_ship("<B1_Motion>")
clean_up_bubs()
score += collision()
if (int(score / BONUS_SCORE)) > bonus:
bonus += 1
end += TIME_LIMIT
show_score(score)
show_time(int(end-time()))
window.update()
sleep(0.01)
c.create_text(MID_X, MID_Y, \
text='PARTY TIME, EXCELLENT', fil='white', font=('Helvetica', 30))
c.create_text(MID_X, MID_Y + 30, \
text='Score: ' + str(score), fill='white')
c.create_text(MID_X, MID_Y + 45, \
text='BONU TIME: ' + str(bonus*TIME_LIMIT), fill='white')
I'm a complete beginner when it comes to python, and have been given an assignment to only use tkinter and the standard libraries to give mouse movement to this "game". I just can't seem to get the right grasp of it. Any suggestions would be appreciated!
The first step is to remove your while loop, and put most of your functionality into a function. Put everything you want to do in a single frame of animation into this function.
Next, call this function on a regular interval using the after command. This allows the event loop to run continuously, which is important for your UI to be responsive. You can do your time() < end calculation inside this function, and use the result to break the cycle once time is up.
It looks something like this:
def draw_one_frame():
if randint(1, BUB_CHANCE) == 1:
create_bubble()
move_bubbles()
# move_ship("<B1_Motion>")
clean_up_bubs()
score += collision()
if (int(score / BONUS_SCORE)) > bonus:
bonus += 1
end += TIME_LIMIT
show_score(score)
show_time(int(end-time()))
if time() < end:
after(10, draw_one_frame)
You can use the first parameter to after to control how many frames per second you wish your program to run at.
Next, you need to handle mouse movement. You do this by creating a binding to the movement of the mouse. You do this outside of the draw_one_frame method. It looks something like this:
c.bind("<B1-Motion>", move_ship)
You also need to remove the infinite loop from move_ship, and also remove the sleep. You simply need to do all the calculations for the current mouse position. The function will be already be looping -- being called once each time the mouse moves.
Finally, you need to call window.mainloop() after all your other code, so that the program can process events. This should be the very last line of your program. It will run until the window is destroyed.