-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of https://github.com/GrantWChapman/Ultima-VII-Ar…
- Loading branch information
Showing
47 changed files
with
589 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.venv |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
from pathlib import Path | ||
|
||
html_header_and_style = r""" | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Image Gallery</title> | ||
<link rel="stylesheet" type="text/css" href="style.css"> | ||
</head> | ||
<body> | ||
<h1>Ultima VII Artwork for use with Exult</h1> | ||
<p> This repository contains all artwork designed to be used in Ultima VII parts one and two through the use of the Exult program. Each piece is available either as a raw .png file or the .shp format for import through Exult Studio. </p> | ||
<p> Exult is available at https://github.com/exult/exult </p> | ||
<p> Ultima VII and Serpent Isle are available for purchase at https://www.gog.com/en/game/ultima_7_complete </p> | ||
<div id="table-of-contents"> | ||
<h2>Table of Contents</h2> | ||
<div class="toc-columns"> | ||
<div class="toc-column"> | ||
<h3><a href="#paperdolls">Paperdolls</a></h3> | ||
<a class="toc-link" href="#paperdolls_accessories">Accessories</a> | ||
<a class="toc-link" href="#paperdolls_ammo">Ammo</a> | ||
<a class="toc-link" href="#paperdolls_armor">Armor</a> | ||
<a class="toc-link" href="#paperdolls_arrows">Arrows</a> | ||
<a class="toc-link" href="#paperdolls_axes">Axes</a> | ||
<a class="toc-link" href="#paperdolls_blowguns">Blowguns</a> | ||
<a class="toc-link" href="#paperdolls_bolts">Bolts</a> | ||
<a class="toc-link" href="#paperdolls_bows">Bows</a> | ||
<a class="toc-link" href="#paperdolls_clothes">Clothes</a> | ||
<a class="toc-link" href="#paperdolls_crossbows">Crossbows</a> | ||
<a class="toc-link" href="#paperdolls_daggers">Daggers</a> | ||
<a class="toc-link" href="#paperdolls_firearms">Firearms</a> | ||
<a class="toc-link" href="#paperdolls_flails">Flails</a> | ||
<a class="toc-link" href="#paperdolls_maces">Maces</a> | ||
<a class="toc-link" href="#paperdolls_polearms">Polearms</a> | ||
<a class="toc-link" href="#paperdolls_shields">Shields</a> | ||
<a class="toc-link" href="#paperdolls_slings">Slings</a> | ||
<a class="toc-link" href="#paperdolls_swords">Swords</a> | ||
<a class="toc-link" href="#paperdolls_thrown">Thrown</a> | ||
<a class="toc-link" href="#paperdolls_wands">Wands</a> | ||
</div> | ||
<div class="toc-column"> | ||
<h3><a href="#shapes">Shapes and sprites</a></h3> | ||
<a class="toc-link" href="#shapes_accessories">Accessories</a> | ||
<a class="toc-link" href="#shapes_armor">Armor</a> | ||
<a class="toc-link" href="#shapes_clothes">Clothes</a> | ||
<a class="toc-link" href="#shapes_shields">Shields</a> | ||
<a class="toc-link" href="#shapes_ammo">Ammo</a> | ||
<a class="toc-link" href="#shapes_arrows">Arrows</a> | ||
<a class="toc-link" href="#shapes_axes">Axes</a> | ||
<a class="toc-link" href="#shapes_blowguns">Blowguns</a> | ||
<a class="toc-link" href="#shapes_bolts">Bolts</a> | ||
<a class="toc-link" href="#shapes_bows">Bows</a> | ||
<a class="toc-link" href="#shapes_crossbows">Crossbows</a> | ||
<a class="toc-link" href="#shapes_daggers">Daggers</a> | ||
<a class="toc-link" href="#shapes_firearms">Firearms</a> | ||
<a class="toc-link" href="#shapes_flails">Flails</a> | ||
<a class="toc-link" href="#shapes_maces">Maces</a> | ||
<a class="toc-link" href="#shapes_polearms">Polearms</a> | ||
<a class="toc-link" href="#shapes_slings">Slings</a> | ||
<a class="toc-link" href="#shapes_swords">Swords</a> | ||
<a class="toc-link" href="#shapes_thrown">Thrown</a> | ||
<a class="toc-link" href="#shapes_wands">Wands</a> | ||
</div> | ||
<div class="toc-column"> | ||
<h3><a href="#gumps">Gumps</a></h3> | ||
</div> | ||
</div> | ||
</div> | ||
""" | ||
|
||
# This is a generic TOC for the script below | ||
# <div id="table-of-contents"> | ||
# <h1>Table of Contents</h1> | ||
# <ul id="toc-list"></ul> | ||
# </div> | ||
|
||
|
||
html_footer = r""" | ||
</body> | ||
</html> | ||
""" | ||
|
||
# To auto-generate a toc in case I change stuff | ||
# <script> | ||
# // Get all h1 and h2 elements on the page | ||
# const headings = document.querySelectorAll('h2, h3'); | ||
# | ||
# // Create a table of contents list | ||
# const tocList = document.getElementById('toc-list'); | ||
# | ||
# // Loop through each heading and add a link to the table of contents | ||
# headings.forEach((heading) => { | ||
# const link = document.createElement('a'); | ||
# link.textContent = heading.textContent; | ||
# link.href = `#${heading.id}`; | ||
# | ||
# // If the heading is an h1, add a class to indicate it's a top-level heading | ||
# if (heading.tagName === 'h2') { | ||
# link.classList.add('top-level'); | ||
# } | ||
# | ||
# const listItem = document.createElement('li'); | ||
# listItem.appendChild(link); | ||
# tocList.appendChild(listItem); | ||
# }); | ||
# | ||
# </script> | ||
|
||
png_prefix = Path("docs") | ||
|
||
def create_image_box(path: Path): | ||
template = """<div class="image-box"> <img src="{path}" alt="{filename}"> <a href="{path}" target="_blank"></a></div>""" | ||
return template.format(path=str(png_prefix / path), filename=path.stem) | ||
|
||
|
||
def add_gallery_container(title: str, images: list[str], html_id: str): | ||
template = """\n<h3 id={id_}>{title}</h3>\n<div class="gallery-container">{images}\n</div>""" | ||
return template.format(images="\n\t".join(images), title=title, id_=html_id) | ||
|
||
|
||
images_paperdolls = list(Path(".").glob("paperdolls*png")) | ||
images_shapes_sprites = list(Path(".").glob("shapes*png")) + list(Path(".").glob("sprites*png")) | ||
gumps = Path('.') / 'gumps.png' | ||
|
||
assert all([i.exists() for i in images_paperdolls]) | ||
assert all([i.exists() for i in images_shapes_sprites]) | ||
assert gumps.exists() | ||
|
||
html = html_header_and_style | ||
|
||
|
||
def get_name(path: Path): | ||
t1 = str(path) | ||
second_half = t1.split("_")[1] | ||
name_itself = second_half.split(".")[0] | ||
return name_itself | ||
|
||
|
||
html += '\n<h2 id="paperdolls">Paperdolls</h2>\n' | ||
for image in images_paperdolls: | ||
html += add_gallery_container( | ||
get_name(image), | ||
[create_image_box(image)], | ||
"paperdolls_" + get_name(image).lower(), | ||
) | ||
|
||
html += '\n<h2 id="shapes">Shapes and sprites</h2>\n' | ||
for image in images_shapes_sprites: | ||
html += add_gallery_container( | ||
get_name(image), [create_image_box(image)], "shapes_" + get_name(image).lower() | ||
) | ||
|
||
html += '\n<h2 id="gumps">Gumps</h2>\n' | ||
html += add_gallery_container("", [create_image_box(gumps)], "") | ||
html += html_footer | ||
|
||
with open("../index.html", "w") as f: | ||
f.write(html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import subprocess | ||
import drawsvg as dw | ||
from PIL import Image | ||
from pathlib import Path | ||
import math | ||
|
||
N_COLS = 10 # Default number of columns in the merged images | ||
N_COLS_GUMPS = 3 # Number of columns for the Gumps, which are wider than the other images | ||
INKSCAPE_PATH = r"C:\Program Files\Inkscape\bin\inkscape.exe" | ||
|
||
FOLDERS_PAPERDOLLS = [ | ||
Path("../Ultima Accessories/Art/Paperdoll"), | ||
Path("../Ultima Armor/Art/Paperdolls"), | ||
Path("../Ultima Clothes/Art/Paperdolls"), | ||
Path("../Ultima Shields/Art/Paperdolls"), | ||
] | ||
|
||
|
||
FOLDERS_SHAPES = [ | ||
Path("../Ultima Accessories/Art/Shapes"), | ||
Path("../Ultima Armor/Art/Shapes"), | ||
Path("../Ultima Clothes/Art/Shapes"), | ||
Path("../Ultima Shields/Art/Shapes"), | ||
] | ||
|
||
FOLDERS_WEAPON_PAPERDOLLS = list(Path("../Ultima Weapons/Art/Paperdolls").glob("*")) | ||
FOLDERS_WEAPON_SPRITES = list(Path("../Ultima Weapons/Art/Sprites").glob("*")) | ||
|
||
FOLDER_GUMPS = Path('../Ultima Gumps/Art') | ||
|
||
|
||
def create_drawing(images_paths: list[Path], n_cols=N_COLS): | ||
widths = [] | ||
heights = [] | ||
for image in images_paths: | ||
i = Image.open(image) | ||
width, height = i.size | ||
widths.append(width) | ||
heights.append(height) | ||
i.close() | ||
|
||
max_width = max(widths) | ||
max_height = max(heights) | ||
|
||
page_width = max_width * n_cols | ||
page_height = max_height * math.ceil(len(images_paths) / n_cols) | ||
|
||
drawing = dw.Drawing(page_width, page_height, origin=(0, 0)) | ||
rolling_xpos = 0 | ||
rolling_ypos = 0 | ||
|
||
for image, w, h in zip(images_paths, widths, heights): | ||
drawing.append( | ||
dw.Image( | ||
rolling_xpos, | ||
rolling_ypos, | ||
w, | ||
h, | ||
image, | ||
embed=False, | ||
preserveAspectRatio=False, | ||
) | ||
) | ||
rolling_xpos += max_width | ||
if rolling_xpos >= page_width: | ||
rolling_xpos = 0 | ||
rolling_ypos += max_height | ||
|
||
return drawing | ||
|
||
|
||
def try_to_save(output_image_path: Path, drawing: dw.Drawing): | ||
try: | ||
drawing.save_png(output_image_path.with_suffix(".png")) # Requires Cairo. | ||
except Exception as e: # Assuming the only error thrown is Cairo not being found | ||
print( | ||
"Problem when saving png, probably related to Cairo not being found. " | ||
"Switching to inkscape and saving SVGs for later conversion" | ||
) | ||
svg_path = output_image_path.with_suffix(".svg") | ||
drawing.save_svg(svg_path) | ||
if not Path(INKSCAPE_PATH).exists(): | ||
print("Inkscape not found. Only saving the svgs") | ||
return | ||
a = subprocess.run([INKSCAPE_PATH, "--export-type=png", str(svg_path)], capture_output=True) | ||
if a.stderr: | ||
print("Inkscape error: ", a.stderr) | ||
|
||
|
||
def process_folder(folder: Path, output_path: Path, n_cols=N_COLS, clean_svg: bool = False): | ||
images = sorted(list(folder.glob("*.png"))) | ||
drawing = create_drawing(images, n_cols) | ||
try_to_save(output_path, drawing) | ||
if clean_svg: | ||
output_path.with_suffix(".svg").unlink(missing_ok=True) | ||
|
||
|
||
def main(): | ||
for folder in FOLDERS_PAPERDOLLS: | ||
process_folder( | ||
folder, | ||
Path("paperdolls_" + folder.parents[1].stem.split(" ")[1] + ".png"), | ||
clean_svg=True, | ||
) | ||
for folder in FOLDERS_SHAPES: | ||
process_folder( | ||
folder, | ||
Path("shapes_" + folder.parents[1].stem.split(" ")[1] + ".png"), | ||
clean_svg=True, | ||
) | ||
for folder in FOLDERS_WEAPON_PAPERDOLLS: | ||
process_folder(folder, Path("paperdolls_" + folder.stem + ".png"), clean_svg=True) | ||
for folder in FOLDERS_WEAPON_SPRITES: | ||
process_folder(folder, Path("sprites_" + folder.stem + ".png"), clean_svg=True) | ||
process_folder(FOLDER_GUMPS, Path("gumps.png"), clean_svg=True, n_cols=N_COLS_GUMPS) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.