Skip to content

Commit e18f6f6

Browse files
committed
Replace file-based operations with BytesIO
1 parent dca1bb8 commit e18f6f6

23 files changed

+404
-621
lines changed

.env

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Set location of ChromeDriver installation directory
2+
CHROME_PATH='/usr/bin/chromedriver'

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ celerybeat.pid
122122
*.sage.py
123123

124124
# Environments
125-
.env
125+
# .env
126126
.venv
127127
env/
128128
venv/
@@ -164,3 +164,6 @@ cython_debug/
164164

165165
# macOS
166166
.DS_Store
167+
168+
#portfoliofy
169+
api/output/

.pylintrc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[MESSAGES CONTROL]
22
disable=line-too-long
3-
disable=protected-access
4-
disable=bare-except
3+
4+
# protected-access
5+
# bare-except

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,10 @@ portfoliofy/
8888
│ │ └── __init__.py
8989
│ │
9090
│ ├── domain/
91-
│ │ ├── services/
92-
│ │ │ └── __init__.py
9391
│ │ └── schemas/
94-
│ │
95-
│ ├── output/
92+
│ │ │ └── __init__.py
93+
│ │ └── services/
94+
│ │ └── __init__.py
9695
│ │
9796
│ ├── routers/
9897
│ │ ├── __init__.py

api/core/utils/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
from .utils import get_final
1212
from .utils import cleanup
1313

14-
# Define what should be available when using "from .helpers import *"
14+
15+
# Define what should be available when using "from .utils import *"
1516
__all__ = ['get_screenshot',
1617
'get_screenshot_full',
1718
'get_screenshot_full_chrome',

api/core/utils/utils.py

Lines changed: 74 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
# Python Standard Libraries
66
import base64
7+
from io import BytesIO
78
import json
89
import os
910
from time import sleep
@@ -16,6 +17,7 @@
1617
from selenium.webdriver.chrome.options import Options
1718

1819

20+
CHROME_PATH = os.environ.get('CHROME_INSTALL_DIR')
1921

2022

2123

@@ -24,7 +26,9 @@
2426

2527

2628

27-
def get_screenshot(url, wait, directory, settings_devices):
29+
30+
31+
def get_screenshot(url, wait, settings_devices):
2832
"""
2933
TD
3034
"""
@@ -37,32 +41,32 @@ def get_screenshot(url, wait, directory, settings_devices):
3741

3842
try:
3943
# Set Chromedriver path
40-
service = Service(executable_path="/usr/bin/chromedriver")
44+
service = Service(executable_path=CHROME_PATH)
4145

4246
# Open Chrome webdriver
4347
driver = webdriver.Chrome(service=service, options=options)
48+
4449
except:
4550
# Open Chrome webdriver
4651
driver = webdriver.Chrome(options=options)
4752

4853
# Open Chrome webdriver
4954
driver = webdriver.Chrome(options=options)
5055

51-
# Take screenshot
52-
driver.get(url)
53-
sleep(wait)
54-
driver.save_screenshot(f"{directory}/{settings_devices['filename_large']}")
56+
try:
57+
driver.get(url)
58+
sleep(wait)
5559

56-
# Retrieve screenshot
57-
screenshot = driver.get_screenshot_as_png()
60+
# Take screenshot
61+
screenshot = driver.get_screenshot_as_png()
5862

59-
# Take screenshot
60-
driver.close()
63+
return screenshot
6164

62-
return screenshot
65+
finally:
66+
driver.quit()
6367

6468

65-
def get_screenshot_full(url, wait, directory, settings_devices):
69+
def get_screenshot_full(url, wait):
6670
"""
6771
TD
6872
"""
@@ -73,30 +77,29 @@ def get_screenshot_full(url, wait, directory, settings_devices):
7377

7478
try:
7579
# Set Chromedriver path
76-
service = Service(executable_path="/usr/bin/chromedriver")
80+
service = Service(executable_path=CHROME_PATH)
7781

7882
# Open Chrome webdriver
7983
driver = webdriver.Chrome(service=service, options=options)
8084
except:
8185
# Open Chrome webdriver
82-
driver = webdriver.Chrome(options=options)
86+
driver = webdriver.Chrome(options=options)
8387

8488
# Open Chrome webdriver
8589
driver = webdriver.Chrome(options=options)
8690

87-
driver.get(url)
88-
89-
sleep(wait)
91+
try:
92+
driver.get(url)
93+
sleep(wait)
9094

91-
fname_out_full_screenshot_png = settings_devices["filename_large"]
95+
# Take screenshot
96+
screenshot = get_screenshot_full_chrome(driver)
9297

93-
png = get_screenshot_full_chrome(driver)
94-
with open(f"{directory}/{fname_out_full_screenshot_png}", 'wb') as f:
95-
f.write(png)
98+
return screenshot
9699

97-
driver.close()
100+
finally:
98101

99-
return 1
102+
driver.quit()
100103

101104

102105
def get_screenshot_full_chrome(driver) :
@@ -140,97 +143,86 @@ def evaluate(script):
140143
return base64.b64decode(screenshot['data'])
141144

142145

143-
def get_base(post, directory, svg, svg_fname, png_fname):
146+
def get_base(post, svg):
144147
"""
145-
TD
148+
Creates base image from SVG and returns PNG bytes
146149
"""
147-
# Create SVG file
148-
with open(f"{directory}/{svg_fname}", "w", encoding="utf-8") as file:
149-
file.write(svg)
150+
with BytesIO() as svg_io, BytesIO() as png_io:
150151

151-
# Convert to SVG to PNG
152-
svg2png(url=f"{directory}/{svg_fname}",
153-
write_to=f"{directory}/{png_fname}",
154-
background_color=post["doc_fill_color"])
152+
svg_io.write(svg.encode())
153+
svg_io.seek(0)
155154

156-
# Delete SVG file
157-
cleanup(directory, svg_fname)
155+
svg2png(file_obj=svg_io,
156+
write_to=png_io,
157+
background_color=post["doc_fill_color"])
158158

159-
return 1
159+
return png_io.getvalue()
160160

161161

162-
def get_overlay(directory, fname_input, fname_output, new_width, height_crop):
162+
def get_overlay(screenshot_bytes, new_width, height_crop):
163163
"""
164-
TD
164+
Creates overlay image from screenshot and returns PNG bytes
165165
"""
166-
# Open the PNG image
167-
image = Image.open(f"{directory}/{fname_input}")
166+
with BytesIO(screenshot_bytes) as img_io, BytesIO() as output:
167+
image = Image.open(img_io)
168168

169-
# Determine aspect ratio
170-
aspect_ratio = image.height / image.width
169+
# Resize
170+
aspect_ratio = image.height / image.width
171+
new_height = int(new_width * aspect_ratio)
172+
resized = image.resize((new_width, new_height))
171173

172-
# Set new height
173-
new_height = int(new_width * aspect_ratio)
174+
# Crop
175+
width, height = resized.size
176+
cropped = resized.crop((0, 0, width, abs(height - (height - height_crop))))
174177

175-
# Resize the image
176-
resized_image = image.resize((new_width, new_height))
178+
# Save to bytes
179+
cropped.save(output, format='PNG')
177180

178-
# Crop image
179-
width, height = resized_image.size
180-
cropped_image = resized_image.crop((0, 0, width, abs(height - (height - height_crop))))
181+
overlay = output.getvalue()
181182

182-
# Save the cropped image
183-
cropped_image.save(f"{directory}/{fname_output}")
183+
return overlay
184184

185-
return 1
186185

187-
188-
def get_final_temp(base, overlay, lat, lng, directory_path, new_file_name):
186+
def get_final_temp(base_bytes, overlay_bytes, lat, lng):
189187
"""
190-
TD
188+
Combines base and overlay images and returns PNG bytes
191189
"""
192-
# Open the base image
193-
base_image = Image.open(base)
190+
with BytesIO(base_bytes) as base_io, \
191+
BytesIO(overlay_bytes) as overlay_io, \
192+
BytesIO() as output:
194193

195-
# Open the overlay image
196-
overlay_image = Image.open(overlay)
194+
base_img = Image.open(base_io)
195+
overlay_img = Image.open(overlay_io)
197196

198-
# Set coordinates of top-left corner
199-
box = (lat, lng)
197+
base_img.paste(overlay_img, (lat, lng))
198+
base_img.save(output, format='PNG')
200199

201-
# Paste overlay image on top of base image
202-
base_image.paste(overlay_image, box)
200+
final_temp = output.getvalue()
203201

204-
# Save image
205-
base_image.save(f"{directory_path}/{new_file_name}")
202+
return final_temp
206203

207-
return f"{directory_path}/{new_file_name}"
208204

209-
210-
def get_final(directory, filename_input, filename_output, post):
205+
def get_final(image_bytes, post):
211206
"""
212-
TD
207+
Adds padding to image and returns final PNG bytes
213208
"""
214-
right = post["doc_pad_h"]
215-
left = post["doc_pad_h"]
216-
top = post["doc_pad_v"]
217-
bottom = post["doc_pad_v"]
218-
color = post["doc_fill_color"]
219-
220-
image = Image.open(f"{directory}/{filename_input}")
209+
with BytesIO(image_bytes) as img_io, BytesIO() as output:
221210

222-
width, height = image.size
211+
image = Image.open(img_io)
223212

224-
new_width = width + right + left
225-
new_height = height + top + bottom
213+
width, height = image.size
214+
right = left = post["doc_pad_h"]
215+
top = bottom = post["doc_pad_v"]
226216

227-
result = Image.new(image.mode, (new_width, new_height), color)
217+
new_width = width + right + left
218+
new_height = height + top + bottom
228219

229-
result.paste(image, (left, top))
220+
result = Image.new(image.mode, (new_width, new_height), post["doc_fill_color"])
221+
result.paste(image, (left, top))
230222

231-
result.save(f"{directory}/{filename_output}")
223+
result.save(output, format='PNG')
232224

233-
return 1
225+
return output.getvalue()
234226

235227

236228
def cleanup(directory_path, file):

api/domain/schemas/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@
33
"""
44

55
from .schemas import PortfoliofyRequest
6+
7+
8+
# Define what should be available when using "from .schemas import *"
9+
__all__ = ['PortfoliofyRequest']

api/domain/schemas/schemas.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ class PortfoliofyRequest(BaseModel):
1717
"""
1818
TD
1919
"""
20-
# pylint: disable-all
2120
request: bool = Field(False, description='Request flag')
2221
remote_url: HttpUrl = Field("https://ggeerraarrdd.github.io/", description="Valid and accessible URL")
2322
wait: conint(gt=0, lt=101) = Field(2, description="Wait time for screenshot") # type: ignore[reportInvalidTypeForm]

api/domain/services/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,12 @@
88
from .output_full import process_request_full
99
from .output_movie import process_request_movie
1010
from .output_screenshots import process_request_screenshots
11+
12+
13+
# Define what should be available when using "from .services import *"
14+
__all__ = ['process_request_main',
15+
'process_request_browser',
16+
'process_request_mobiles',
17+
'process_request_full',
18+
'process_request_movie',
19+
'process_request_screenshots']

0 commit comments

Comments
 (0)