Skip to content

Commit 0d13222

Browse files
authored
Merge pull request #2669 from adafruit/MatrixPortalS3_Flight_Proximity_Tracker
adding logo script
2 parents 2ab4189 + 792616e commit 0d13222

File tree

3 files changed

+175
-1
lines changed

3 files changed

+175
-1
lines changed

MatrixPortal_S3_Flight_Proximity_Tracker/code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
GAP_BETWEEN_ICONS = 15 # Gap between the icons
3535
NUMBER_OF_ICONS = 2 # Number of icons to display
36-
PLACEHOLDER_ICON_PATH = "/airline_logos/placeholder.bmp"
36+
PLACEHOLDER_ICON_PATH = "/placeholder_image/placeholder.bmp"
3737

3838
# --- Text Properties ---
3939
TEXT_START_X = ICON_WIDTH + 4
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
# Written by Liz Clark (Adafruit Industries) with OpenAI ChatGPT v4 Aug 3rd, 2023 build
6+
# https://help.openai.com/en/articles/6825453-chatgpt-release-notes
7+
8+
# https://chat.openai.com/share/2fabba2b-3f17-4ab6-a4d9-58206a3b9916
9+
10+
# process() function originally written by Phil B. for Adafruit Industries
11+
# https://raw.githubusercontent.com/adafruit/Adafruit_Media_Converters/master/protomatter_dither.py
12+
13+
# Based on Airline-Logos Scraper by Cal Stephens, 2017 MIT License
14+
# https://github.com/calda/Airline-Logos
15+
16+
import os
17+
import math
18+
import requests
19+
from PIL import Image
20+
21+
# directory to match CircuitPython code folder names
22+
bitmap_directories = "airline_logos"
23+
24+
img_width = 32
25+
img_height = 32
26+
27+
chars = ["A", "B", "C", "D", "E",
28+
"F", "G", "H", "I", "J", "K", "L",
29+
"M", "N", "O", "P", "Q", "R", "S",
30+
"T", "U", "V", "W", "X", "Y", "Z",
31+
"0", "1", "2", "3", "4", "5", "6",
32+
"7", "8", "9"]
33+
# pylint: disable=inconsistent-return-statements
34+
def convert_bytes(num):
35+
"""
36+
this function will convert bytes to MB.... GB... etc
37+
"""
38+
for _ in ['bytes', 'KB', 'MB', 'GB', 'TB']:
39+
if num < 1024.0:
40+
return f"{num:.1f}"
41+
num /= 1024.0
42+
43+
def file_size(file_path):
44+
"""
45+
this function will return the file size
46+
"""
47+
if os.path.isfile(file_path):
48+
file_info = os.stat(file_path)
49+
print(file_info.st_size)
50+
return file_info.st_size
51+
52+
# Constants and function for image processing
53+
GAMMA = 2.6
54+
55+
PASSTHROUGH = ((0, 0, 0),
56+
(255, 0, 0),
57+
(255, 255, 0),
58+
(0, 255, 0),
59+
(0, 255, 255),
60+
(0, 0, 255),
61+
(255, 0, 255),
62+
(255, 255, 255))
63+
64+
def process(filename, output_8_bit=True, passthrough=PASSTHROUGH):
65+
"""Given a color image filename, load image and apply gamma correction
66+
and error-diffusion dithering while quantizing to 565 color
67+
resolution. If output_8_bit is True, image is reduced to 8-bit
68+
paletted mode after quantization/dithering. If passthrough (a list
69+
of 3-tuple RGB values) is provided, dithering won't be applied to
70+
colors in the provided list, they'll be quantized only (allows areas
71+
of the image to remain clean and dither-free).
72+
"""
73+
img = Image.open(filename).convert('RGB')
74+
err_next_pixel = (0, 0, 0)
75+
err_next_row = [(0, 0, 0) for _ in range(img.size[0])]
76+
for row in range(img.size[1]):
77+
for column in range(img.size[0]):
78+
pixel = img.getpixel((column, row))
79+
want = (math.pow(pixel[0] / 255.0, GAMMA) * 31.0,
80+
math.pow(pixel[1] / 255.0, GAMMA) * 63.0,
81+
math.pow(pixel[2] / 255.0, GAMMA) * 31.0)
82+
if pixel in passthrough:
83+
got = (pixel[0] >> 3,
84+
pixel[1] >> 2,
85+
pixel[2] >> 3)
86+
else:
87+
got = (min(max(int(err_next_pixel[0] * 0.5 +
88+
err_next_row[column][0] * 0.25 +
89+
want[0] + 0.5), 0), 31),
90+
min(max(int(err_next_pixel[1] * 0.5 +
91+
err_next_row[column][1] * 0.25 +
92+
want[1] + 0.5), 0), 63),
93+
min(max(int(err_next_pixel[2] * 0.5 +
94+
err_next_row[column][2] * 0.25 +
95+
want[2] + 0.5), 0), 31))
96+
err_next_pixel = (want[0] - got[0],
97+
want[1] - got[1],
98+
want[2] - got[2])
99+
err_next_row[column] = err_next_pixel
100+
rgb565 = ((got[0] << 3) | (got[0] >> 2),
101+
(got[1] << 2) | (got[1] >> 4),
102+
(got[2] << 3) | (got[2] >> 2))
103+
img.putpixel((column, row), rgb565)
104+
105+
if output_8_bit:
106+
img = img.convert('P', palette=Image.ADAPTIVE)
107+
108+
img.save(filename.split('.')[0] + '.bmp')
109+
110+
# Create a base directory to store the logos if it doesn't exist
111+
base_dir = 'airline_logos'
112+
if not os.path.exists(base_dir):
113+
os.makedirs(base_dir)
114+
115+
# Loop through each combo of characters to find all of the airlines
116+
# this takes a while..
117+
for f in range(len(chars)):
118+
for s in range(len(chars)):
119+
# Set the URL for IATA
120+
# pylint: disable=line-too-long
121+
url = f"https://content.r9cdn.net/rimg/provider-logos/airlines/v/{chars[f]}{chars[s]}.png?crop=false&width=300&height=300"
122+
print(f"Downloading logo for {chars[f]}{chars[s]} from IATA...")
123+
124+
img_path_png = os.path.join(base_dir, f"{chars[f]}{chars[s]}.png")
125+
response = requests.get(url, stream=True, timeout=60)
126+
try:
127+
with open(img_path_png, 'wb') as file:
128+
for chunk in response.iter_content(chunk_size=1024):
129+
file.write(chunk)
130+
131+
z = os.stat(img_path_png)
132+
print(z.st_size)
133+
if z.st_size <= 2506:
134+
print("deleting empty file")
135+
os.remove(img_path_png)
136+
else:
137+
with Image.open(img_path_png) as the_img:
138+
img_resized = the_img.resize((img_width, img_height))
139+
img_resized.save(img_path_png)
140+
process(img_path_png)
141+
142+
# Delete the original .png file
143+
os.remove(img_path_png)
144+
except Exception: # pylint: disable=broad-except
145+
print("file is missing, moving on..")
146+
for t in range(len(chars)):
147+
# Set the URL for ICAO
148+
# pylint: disable=line-too-long
149+
url_1 = f"https://flightaware.com/images/airline_logos/90p/{chars[f]}{chars[s]}{chars[t]}.png"
150+
151+
print(f"Downloading logo for {chars[f]}{chars[s]}{chars[t]} from ICAO...")
152+
153+
img_path_png_0 = os.path.join(base_dir, f"{chars[f]}{chars[s]}{chars[t]}.png")
154+
response_1 = requests.get(url_1, stream=True, timeout=60)
155+
try:
156+
with open(img_path_png_0, 'wb') as file:
157+
for chunk in response_1.iter_content(chunk_size=1024):
158+
file.write(chunk)
159+
160+
z = os.stat(img_path_png_0)
161+
print(z.st_size)
162+
if z.st_size <= 2506:
163+
print("deleting empty file")
164+
os.remove(img_path_png_0)
165+
else:
166+
with Image.open(img_path_png_0) as the_img:
167+
img_resized = the_img.resize((img_width, img_height))
168+
img_resized.save(img_path_png_0)
169+
process(img_path_png_0)
170+
171+
# Delete the original .png file
172+
os.remove(img_path_png_0)
173+
except Exception: # pylint: disable=broad-except
174+
print("file is missing, moving on..")
Binary file not shown.

0 commit comments

Comments
 (0)