File:Leonardo da Vinci monument in Milan.svg
Size of this PNG preview of this SVG file: 376 × 599 pixels. Other resolutions: 150 × 240 pixels | 301 × 480 pixels | 482 × 768 pixels | 642 × 1,024 pixels | 1,285 × 2,048 pixels | 512 × 816 pixels.
Original file (SVG file, nominally 512 × 816 pixels, file size: 1.84 MB)
This file is from Wikimedia Commons and may be used by other projects. The description on its file description page there is shown below.
Summary
DescriptionLeonardo da Vinci monument in Milan.svg |
English: Interactive SVG by CMG Lee of the Leonardo da Vinci monument in Milan. Move left and right over the SVG image to rotate the 3D view. |
Source | Own work |
Author | Cmglee |
Other versions | Derivative works of this file: Monumento a Leonardo da Vinci a Milano.svg |
interactive_svg_filmstrip.py
#!/usr/bin/env python
import re, json
## http://stackoverflow.com/questions/3503879
import subprocess, sys
def system(command, is_verbose=False):
if (is_verbose): sys.stdout.write(command) ## write omits newline
stdout = str(subprocess.check_output(command, shell=True))
if (is_verbose): print(": " + stdout)
return stdout
import os.path ## to check if file exists
def mkdir_cache(is_refresh_cache=False, is_verbose=False, suffix='.cache/'):
basename = __file__[:__file__.rfind('.')]
dir_cache = basename + suffix
if (is_refresh_cache):
for (dir, dirs, filenames) in os.walk(dir_cache, topdown=False): os.rmdir(dir)
if (is_verbose): print("delete {dir_cache}".format(**locals()))
if (not os.path.exists(dir_cache)):
if (is_verbose): print("make {dir_cache}".format(**locals()))
os.makedirs(dir_cache)
elif (is_verbose): print("{dir_cache} already exists".format(**locals()))
return dir_cache
## http://www.techrepublic.com/article/parsing-data-from-the-web-in-python/
try: import urllib2 ## for web access
except ImportError: import urllib.request as urllib2
import time ## for sleep
def read_webpage(url, path_cache='', is_refresh_cache=False, is_verbose=False):
dir_cache = mkdir_cache(is_refresh_cache=is_refresh_cache, is_verbose=is_verbose)
if (not path_cache): path_cache = dir_cache + urllib2.quote(url, safe='')
if (is_refresh_cache or (not os.path.isfile(path_cache))):
html = urllib2.urlopen(url).read()
file_html = open(path_cache, 'wb')
file_html.write(html)
if (is_verbose): print("fetch {url} into {path_cache}".format(**locals()))
time.sleep(1) ## avoid rate-limit-exceeded error
else:
file_html = open(path_cache, 'rb')
html = file_html.read()
if (is_verbose): print("read from {path_cache}".format(**locals()))
file_html.close()
return html
## http://stackoverflow.com/questions/3715493
import base64
def base64_encode(path):
with open(path, 'rb') as file: return base64.b64encode(file.read()).decode('ascii')
def make_svg(url, increment, message_action):
if (message_action == '3D' ): message_action = 'to rotate the 3D view'
if (message_action == 'time'): message_action = 'to move through time'
dir_cache = mkdir_cache()
filename = url[url.rfind('/')+1:]
if (url.find('://') > 0): ## assume URLs have "://" and folder paths don't
is_folder = False
dir_frame = dir_cache
## Get image URL if description page URL given
if (filename.lower().find('file:') == 0):
filename = filename[filename.rfind(':') + 1:]
path_html = '{dir_cache}{filename}.htm'.format(**locals())
html = read_webpage(url, path_html, is_verbose=True)
url = 'http:' + re.search(r'//upload\.[^"]+' + filename, html).group(0)
print(url)
## Fetch image if needed
basename = filename[:filename.rfind('.')]
path_gif = dir_cache + filename
path_basename = path_gif[:path_gif.rfind('.')]
read_webpage(url, path_gif, is_verbose=True)
## Extract GIF animation frames if needed
if (os.path.isfile('{dir_cache}{basename}-0.png'.format(**locals()))):
print("skip extracting GIF animation frames")
else:
print("extract GIF animation frames")
system('magick "{path_gif}" -coalesce "{path_basename}.png"'.format(**locals()), is_verbose=True)
else:
is_folder = True
dir_frame = url.strip('/') + '/'
basename = url[url.strip('/').rfind('/')+1:]
## Base64-encode frames if needed
path_json = dir_cache + basename + '.json'
jsons = {}
n_image = 0
n_frame = 0
if (0):
# if (os.path.isfile(path_json)):
file_json = open(path_json, 'r')
jsons = json.loads(file_json.read())
n_frame = jsons['n_frame']
out_image = jsons['out_image']
width_image = jsons['width_image']
height_image = jsons['height_image']
else:
## Count frames
n_image = 0
if (is_folder):
path_images = ['{dir_frame}{filename}'.format(**locals()) for filename in os.listdir(dir_frame)]
else:
path_images = ['{dir_frame}{path}'.format(**locals()) for path in os.listdir(dir_frame) if path.find(basename) == 0 and path[-3:] == 'png']
# Natural sort based on http://stackoverflow.com/a/5967539
path_images = sorted(path_images, key=lambda x:[int(c) if c.isdigit() else c for c in re.split('(\d+)', x)])
n_image = len(path_images)
## Base64-encode relevant frames
n_frame = int(n_image / abs(increment))
out_images = []
for i_frame in range(n_frame):
i_image = i_frame * increment + (0 if (increment > 0) else n_image + increment)
path_frame = path_images[i_image]
stdout = system('magick "{path_frame}" info:'.format(**locals()), is_verbose=True)
(width_image, height_image) = [int(dim) for dim in re.search(r'\d+x\d+', stdout).group(0).split('x')]
base64_encoded = base64_encode(path_frame)
out_images.append('''\
<image id="image_{i_frame}" x="0" y="0" width="{width_image}" height="{height_image}" xlink:href="data:image/png;base64,{base64_encoded}"/>\
'''.format(**locals()))
out_image = '\n'.join(out_images)
jsons = {'out_image':out_image, 'width_image' :width_image,
'n_frame' :n_frame , 'height_image':height_image}
file_json = open(path_json, 'w')
try: ## use try/finally so that file is closed even if write fails
file_json.write(json.dumps(jsons, indent=1, separators=(',',':')))
finally:
file_json.close()
## Create SVG
out_mains = []
scale_thumbnail = round(1.0 / n_frame, 5)
height_trigger = int(height_image * (scale_thumbnail + 1) + 0.5)
width_trigger = round(width_image * scale_thumbnail, 2)
width_thumbnail = int(width_trigger + 0.9999)
for i_frame in range(n_frame):
x_trigger = round(i_frame * width_trigger, 2)
out_mains.append('''\
<g class="frame">
<g class="content">
<use xlink:href="#image_{i_frame}"/>
</g>
<g class="trigger" transform="translate({x_trigger},{height_image})">
<use xlink:href="#image_{i_frame}" transform="scale({scale_thumbnail})"/>
<use xlink:href="#triggers"/>
</g>
<!-- <title>frame {i_frame}</title> -->
</g>'''.format(**locals()))
out_main = '\n'.join(out_mains)
title = basename.replace('_', ' ')
stroke_width = max(width_image, height_image) / 200
font_size = width_image / 20
x_help = width_image / 2
y_help = height_image / 2
height_thumbnail = height_image * scale_thumbnail - stroke_width / 2
width_images = [width_image * multiple for multiple in range(99)]
## Compile everything into an .svg file
file_out = open(basename + '.svg', 'w')
try: ## use try/finally so that file is closed even if write fails
print("write SVG")
out_title = url.replace('_', ' ') if (is_folder) else 'GIF animation at {url} .'.format(**locals())
file_out.write('''<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 {width_image} {height_trigger}">
<title>{title}</title>
<desc>Interactive SVG by CMG Lee of the {out_title}. Move left and right over the SVG image {message_action}.</desc>
<style type="text/css">
#main {{ font-family:Helvetica,Arial,sans-serif; font-size:{font_size}px; text-anchor:middle;
stroke-width:{stroke_width}; fill:#000000; }}
#trigger {{ stroke:none; fill-opacity:0; }}
.frame .content {{ visibility:hidden; pointer-events:none; fill:#000000; }}
.frame .trigger {{ opacity:0.5; cursor:ew-resize; }}
.frame:hover .content {{ visibility:visible; }}
.frame:hover .trigger {{ opacity:1; pointer-events:auto; font-weight:bold; stroke:#ff0000; }}
</style>
<defs>
<g id="help">
<text x="{x_help}" y="{y_help}" dy="-1ex">Move left and right</text>
<text x="{x_help}" y="{y_help}" dy="1ex">{message_action}</text>
</g>
<rect id="trigger" x="0" y="-4999" width="{width_thumbnail}" height="9999"/>
<g id="triggers">
<rect x="0" y="0" width="{width_thumbnail}" height="{height_thumbnail}" fill="none"/>
<use xlink:href="#trigger"/>
<use xlink:href="#trigger" transform="translate(-{width_images[1]},0)"/>
<use xlink:href="#trigger" transform="translate( {width_images[1]},0)"/>
<use xlink:href="#trigger" transform="translate(-{width_images[2]},0)"/>
<use xlink:href="#trigger" transform="translate( {width_images[2]},0)"/>
<use xlink:href="#trigger" transform="translate(-{width_images[3]},0)"/>
<use xlink:href="#trigger" transform="translate( {width_images[3]},0)"/>
<use xlink:href="#trigger" transform="translate(-{width_images[4]},0)"/>
<use xlink:href="#trigger" transform="translate( {width_images[4]},0)"/>
</g>
{out_image}
</defs>
<g id="main">
<circle cx="0" cy="0" r="9999" fill="#ffffff"/>
<use xlink:href="#image_0" opacity="0.5"/>
<use xlink:href="#help" stroke-opacity="0.5" stroke="#ffffff"/>
<use xlink:href="#help"/>
<g id="frames">
{out_main}
</g>
</g>
</svg>
'''.format(**locals()))
finally:
file_out.close()
n_argv = len(sys.argv)
if (n_argv < 2):
print(("{sys.argv[0]} <URL of GIF animation file or path to folder>\n" +
" [<use every nth GIF frame; negative reverses order> (default: 1)]\n" +
" [<action message or '3D' (default) or 'time'>]")
.format(**locals()))
else:
make_svg( sys.argv[1],
int(sys.argv[2]) if (n_argv > 2) else 1,
sys.argv[3] if (n_argv > 3) else '3D')
Licensing
I, the copyright holder of this work, hereby publish it under the following licenses:
This file is licensed under the Creative Commons Attribution-Share Alike 4.0 International license.
- You are free:
- to share – to copy, distribute and transmit the work
- to remix – to adapt the work
- Under the following conditions:
- attribution – You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- share alike – If you remix, transform, or build upon the material, you must distribute your contributions under the same or compatible license as the original.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled GNU Free Documentation License.http://www.gnu.org/copyleft/fdl.htmlGFDLGNU Free Documentation Licensetruetrue |
You may select the license of your choice.
Items portrayed in this file
depicts
File history
Click on a date/time to view the file as it appeared at that time.
Date/Time | Thumbnail | Dimensions | User | Comment | |
---|---|---|---|---|---|
current | 00:03, 15 August 2016 | 512 × 816 (1.84 MB) | Cmglee | {{Information |Description ={{en|1=Interactive SVG by CMG Lee of the Leonardo da Vinci monument in Milan. Move left and right over the SVG image to rotate the 3D view.}} |Source ={{own}} |Author =Cmglee |Date... |
File usage
There are no pages that use this file.
Metadata
This file contains additional information, probably added from the digital camera or scanner used to create or digitize it.
If the file has been modified from its original state, some details may not fully reflect the modified file.
Short title | Leonardo da Vinci monument in Milan |
---|---|
Image title | Interactive SVG by CMG Lee of the Leonardo da Vinci monument in Milan. Move left and right over the SVG image to rotate the 3D view. |
Width | 100% |
Height | 100% |