Skip to content

Commit 960a0b3

Browse files
committed
Refactor code
1 parent fda11a8 commit 960a0b3

13 files changed

+704
-282
lines changed

.gitignore

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,3 @@
1-
####################################################
2-
# My adds
3-
4-
# macOS
5-
.DS_Store
6-
7-
# Flask
8-
flask_session/
9-
/*_session/
10-
11-
####################################################
12-
131
# Byte-compiled / optimized / DLL files
142
__pycache__/
153
*.py[cod]
@@ -69,7 +57,7 @@ cover/
6957

7058
# Django stuff:
7159
*.log
72-
local_settings.py
60+
# local_settings.py
7361
db.sqlite3
7462
db.sqlite3-journal
7563

@@ -170,3 +158,15 @@ cython_debug/
170158
# and can be added to the global gitignore or merged into this file. For a more nuclear
171159
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
172160
#.idea/
161+
162+
####################################################
163+
# My adds
164+
165+
# macOS
166+
.DS_Store
167+
168+
# Flask
169+
flask_session/
170+
/*_session/
171+
172+
####################################################

README.md

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ Assemble screenshots of web projects for your portfolio
44

55
## Description
66

7-
Once a web project is done, it's time to document your hard work and show it off. _Portfoliofy!_ makes that process easier by doing all the screenshots for you and assembling them together into portfolio-ready files.
7+
Once a web project is done, it's time to document your hard work and show it off. _Portfoliofy_ makes that process easier by doing all the screenshots for you and assembling them together into portfolio-ready files.
88

9-
As of v1.0.0, two files are generated:
9+
As of v2.0.0, the following files can be generated:
1010

11-
* A desktop browser screenshot (2048x1152)
12-
* A collage of screenshots for various devices: desktop (1920x1080), laptop (1280x720), tablet (600x800), mobile (230x490).
11+
* `SCREENSHOTS`
12+
* Four image files of screenshots taken in different viewports (desktop - 2160x1360, laptop - 1440x900, tablet - 768x1024, smartphone - 230x490).
13+
* `MAIN`
14+
* An image file of those screenshots overlaid on top schematic diagrams and then collaged together. (See below for an example ouput.)
15+
* `BROWSER`
16+
* A image file of the desktop screenshot overlaid on top of a schematic diagram. (Scroll to the bottom for an example ouput.)
17+
18+
More coming soon!
1319

1420
![Portfoliofy](/images/portfoliofy1.png)
1521

@@ -23,9 +29,10 @@ ALL CONTENTS IN THIS REPO ARE FOR EDUCATIONAL PURPOSES ONLY.
2329

2430
### Dependencies
2531

32+
* CairoSVG==2.7.1
2633
* Pillow==10.1.0
2734
* Requests==2.31.0
28-
* selenium==4.15.0
35+
* selenium==4.15.2
2936

3037
### Usage
3138

@@ -35,15 +42,36 @@ Clone it!
3542
git clone https://github.com/ggeerraarrdd/portfoliofy.git
3643
```
3744

38-
Go into the project directory and run the command:
45+
Open `local_settings.py` and change the value of `url` to the one you want to portfoliofy.
46+
47+
Then run the following command:
3948

4049
```bash
4150
python portfoliofy.py
4251
```
4352

44-
Enter a valid and accessible URL as requested.
53+
The output files are stored in a subdirectory of the `output` directory.
54+
55+
## Parameters
56+
57+
You can also change the following parameter in `local_settings.py`.
58+
59+
| Parameter | Type | Default value | Value range | Description |
60+
| ----------------- | ------ | ------------- | ------------ | ----------- |
61+
| wait | int | 2 | 0-60 | Time in seconds to allow URL to load before taking screenshot. |
4562

46-
The output files are stored in a directory inside the `output` directory.
63+
The `MAIN` and `BROWSER` output files are generated by default but you can stop this default behavior by changing the value of `request` to `False`. You can also customize the output files.
64+
65+
| Parameter | Type | Default value | Value range | Description |
66+
| ----------------- | ------ | ------------- | ------------ | ----------- |
67+
| request | bool | True | True, False | If TRUE, requested output is processed. |
68+
| format | string | png | png | Format of the final output. |
69+
| doc_pad_h | int | 300 | 0 - 1000 | Left and right padding in pixels of final output. |
70+
| doc_pad_v | int | 200 | 0 - 1000 | Top and bottom padding in pixels of final output. |
71+
| doc_fill_color | string | #FFFFFF | '' | Background color of final output in 6-digit hex. |
72+
| base_stroke_color | string | #23445D | '' | Stroke color of diagram in 6-digit hex. |
73+
| base_fill_color | string | #BAC8D3 | '' | Fill color of diagram in 6-digit hex. |
74+
| screenshots | bool | True | True, False | If TRUE, all screenshots are saved. |
4775

4876
## Author(s)
4977

@@ -57,20 +85,7 @@ The output files are stored in a directory inside the `output` directory.
5785

5886
### Initial Release
5987

60-
The [initial realease](https://github.com/ggeerraarrdd/portfoliofy/releases/tag/v1.0.0) of _Portfoliofy!_ was submitted as the final project for [CS50P: Introduction to Programming with Python](https://cs50.harvard.edu/python/2022/) (HarvardX, 2023).
61-
62-
[Project brief](https://cs50.harvard.edu/python/2022/project/) as of November 2023:
63-
64-
_The design and implementation of your project is entirely up to you, albeit subject to these requirements:_
65-
66-
* _Your project must be implemented in Python._
67-
* _Your project must have a main function and three or more additional functions. At least three of those additional functions must be accompanied by tests that can be executed with pytest._
68-
* _Your main function must be in a file called project.py, which should be in the “root” (i.e., top-level folder) of your project._
69-
* _Your 3 required custom functions other than main must also be in project.py and defined at the same indentation level as main (i.e., not nested under any classes or functions)._
70-
* _Your test functions must be in a file called test_project.py, which should also be in the “root” of your project. Be sure they have the same name as your custom functions, prepended with test (test_custom_function, for example, where custom_function is a function you’ve implemented in project.py)._
71-
* _You are welcome to implement additional classes and functions as you see fit beyond the minimum requirement._
72-
* _Implementing your project should entail more time and effort than is required by each of the course’s problem sets._
73-
* _Any pip-installable libraries that your project requires must be listed, one per line, in a file called requirements.txt in the root of your project._
88+
The [initial realease](https://github.com/ggeerraarrdd/portfoliofy/releases/tag/v1.0.0) of _Portfoliofy_ was submitted as the final project for [CS50P: Introduction to Programming with Python](https://cs50.harvard.edu/python/2022/) (HarvardX, 2023). Read the [project brief](https://cs50.harvard.edu/python/2022/project/) as of November 2023.
7489

7590
### Future Work
7691

helpers.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import os
2+
from selenium import webdriver
3+
from PIL import Image
4+
from time import sleep
5+
import requests
6+
from selenium.webdriver.chrome.options import Options
7+
8+
9+
def get_screenshot(remote_url, wait, directory_path, input):
10+
11+
# Set options
12+
options = Options()
13+
options.add_argument(f"--window-size={input['width_large']},{input['height_large']}")
14+
options.add_argument(f"--no-sandbox")
15+
options.add_argument(f"--headless")
16+
17+
# Open Chrome webdriver
18+
driver = webdriver.Chrome(options=options)
19+
20+
# Take screenshot
21+
driver.get(remote_url)
22+
sleep(wait)
23+
driver.save_screenshot(f"{directory_path}/{input['filename_large']}")
24+
25+
# Take screenshot
26+
driver.close()
27+
28+
return f"{input['filename_large']} screenshot saved"
29+
30+
31+
def get_screenshot_resized(directory_main, directory_screenshots, filename_input, filename_output, new_width, height_crop):
32+
33+
# Open the PNG image
34+
image = Image.open(f"{directory_screenshots}/{filename_input}")
35+
36+
# Determine aspect ratio
37+
# TODO Make this as an argument
38+
aspect_ratio = image.height / image.width
39+
40+
# Set new height
41+
new_height = int(new_width * aspect_ratio)
42+
43+
# Resize the image
44+
resized_image = image.resize((new_width, new_height))
45+
46+
# Crop image
47+
width, height = resized_image.size
48+
cropped_image = resized_image.crop((0, 0, width, abs(height - (height - height_crop))))
49+
50+
# Save the cropped image
51+
cropped_image.save(f"{directory_main}/{filename_output}")
52+
53+
return f"{filename_output} screenshots saved"
54+
55+
56+
def get_screenshot_resized_overlaid(base, overlay, lat, lng, directory_path, new_file_name):
57+
58+
# Open the base image
59+
base_image = Image.open(base)
60+
61+
# Open the overlay image
62+
overlay_image = Image.open(overlay)
63+
64+
# Set coordinates of top-left corner
65+
box = (lat, lng)
66+
67+
# Paste overlay image on top of base image
68+
base_image.paste(overlay_image, box)
69+
70+
# Save image
71+
base_image.save(f"{directory_path}/{new_file_name}")
72+
73+
return f"{directory_path}/{new_file_name}"
74+
75+
76+
def get_output_padded(directory, filename_input, filename_output, right, left, top, bottom, color):
77+
78+
image = Image.open(f"{directory}/{filename_input}")
79+
80+
width, height = image.size
81+
82+
new_width = width + right + left
83+
new_height = height + top + bottom
84+
85+
result = Image.new(image.mode, (new_width, new_height), color)
86+
87+
result.paste(image, (left, top))
88+
89+
result.save(f"{directory}/{filename_output}")
90+
91+
return 1
92+
93+
94+
def cleanup(directory_path, file):
95+
try:
96+
os.remove(f"{directory_path}/{file}")
97+
return f"{file} has been deleted"
98+
except FileNotFoundError:
99+
return f"{file} not in directory"
100+

local_settings.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
user_input = {
2+
"url": "https://www.nps.gov/",
3+
"wait": 2,
4+
"output_main": {
5+
"request": True,
6+
"format": "png",
7+
"doc_pad_h": 300,
8+
"doc_pad_v": 200,
9+
"doc_fill_color": "#FFFFFF",
10+
"base_stroke_color": "#23445D",
11+
"base_fill_color": "#BAC8D3",
12+
"screenshots": True,
13+
},
14+
"output_browser": {
15+
"request": True,
16+
"format": "png",
17+
"doc_pad_h": 300,
18+
"doc_pad_v": 200,
19+
"doc_fill_color": "#FFFFFF",
20+
"base_stroke_color": "#23445D",
21+
"base_fill_color": "#BAC8D3",
22+
"screenshots": True,
23+
},
24+
}
25+
26+
27+
# ################################################## #
28+
#
29+
# DO NOT EDIT below this comment.
30+
#
31+
# ################################################## #
32+
system_input = {
33+
"desktop": {
34+
"filename_large": "screenshot_desktop_large.png",
35+
"width_large": 2160,
36+
"height_large": 1360,
37+
"filename_medium": "screenshot_desktop_medium.png",
38+
"width_medium": 2048,
39+
"height_medium": None,
40+
"medium_height_crop": 1152,
41+
"filename_small": "screenshot_desktop_small.png",
42+
"width_small": 1920,
43+
"height_small": None,
44+
"small_height_crop": 1080,
45+
},
46+
"laptop": {
47+
"filename_large": "screenshot_laptop_large.png",
48+
"width_large": 1440,
49+
"height_large": 900,
50+
"filename_medium": "screenshot_laptop_medium.png",
51+
"width_medium": None,
52+
"height_medium": None,
53+
"medium_height_crop": None,
54+
"filename_small": "screenshot_laptop_small.png",
55+
"width_small": 1280,
56+
"height_small": None,
57+
"small_height_crop": 720,
58+
},
59+
"tablet": {
60+
"filename_large": "screenshot_tablet_large.png",
61+
"width_large": 768,
62+
"height_large": 1024,
63+
"filename_medium": "screenshot_tablet_medium.png",
64+
"width_medium": None,
65+
"height_medium": None,
66+
"medium_height_crop": None,
67+
"filename_small": "screenshot_tablet_small.png",
68+
"width_small": 600,
69+
"height_small": None,
70+
"small_height_crop": 800,
71+
},
72+
"smartphone": {
73+
"filename_large": "screenshot_smartphone_large.png",
74+
"width_large": 430,
75+
"height_large": 932,
76+
"filename_medium": "screenshot_smartphone_medium.png",
77+
"width_medium": None,
78+
"height_medium": None,
79+
"medium_height_crop": None,
80+
"filename_small": "screenshot_smartphone_small.png",
81+
"width_small": 230,
82+
"height_small": None,
83+
"small_height_crop": 490,
84+
},
85+
}

output/devices_desktop.png

-153 KB
Binary file not shown.

output/devices_layer_1.png

-297 KB
Binary file not shown.

output/devices_layer_2.png

-25.3 KB
Binary file not shown.

output/devices_layer_3.png

-17.2 KB
Binary file not shown.

output/devices_layer_4.png

-7.28 KB
Binary file not shown.

0 commit comments

Comments
 (0)