mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 17:19:37 +02:00
Logo Tools (#158)
* Logo Tools * Moved to /tools/logo; Checks dependencies first and stops if they are not there; Added information about 3_remove_branding_from_projectpage.sh in README ; reordered the commands of 1_convert.sh to avoid the logo-horizontal.png problem
This commit is contained in:
15
tools/logo/.gitignore
vendored
Normal file
15
tools/logo/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
android-chrome-192x192.png
|
||||
android-chrome-512x512.png
|
||||
apple-touch-icon.png
|
||||
favicon-16x16.png
|
||||
favicon-32x32.png
|
||||
favicon-compiled.svg
|
||||
favicon-compiling.svg
|
||||
favicon-error.svg
|
||||
favicon.ico
|
||||
favicon.svg
|
||||
img
|
||||
logo-horizontal.png
|
||||
logo_sw.svg
|
||||
mask-favicon.svg
|
||||
overleaf_og_logo.png
|
||||
78
tools/logo/1_convert.sh
Executable file
78
tools/logo/1_convert.sh
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit immediately if a command exits with a non-zero status
|
||||
set -e
|
||||
|
||||
python3 check_dependency.py
|
||||
|
||||
mkdir -p img/ol-brand
|
||||
|
||||
echo "============================================================"
|
||||
echo "Logo Conversion Script"
|
||||
echo "============================================================"
|
||||
echo ""
|
||||
|
||||
# 1. Validation Checks
|
||||
if [ ! -f "logo.svg" ] || [ ! -f "logo_full.svg" ]; then
|
||||
echo "ERROR: Required SVG files (logo.svg or logo_full.svg) not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ Found source SVGs"
|
||||
|
||||
# 2. Generate Favicons
|
||||
cp logo.svg favicon.svg
|
||||
python3 generate_favicons.py favicon.svg
|
||||
|
||||
# 3. Create Black/White/Grey versions
|
||||
echo "Creating black/white versions..."
|
||||
python3 create_sw_versions.py logo.svg logo_sw.svg "#000000"
|
||||
python3 create_sw_versions.py logo.svg mask-favicon.svg "#000000"
|
||||
python3 create_sw_versions.py logo_full.svg img/ol-brand/overleaf-black.svg "#000000"
|
||||
python3 create_sw_versions.py logo.svg img/ol-brand/overleaf-o-white.svg "#FFFFFF"
|
||||
python3 create_sw_versions.py logo_full.svg img/ol-brand/overleaf-white.svg "#FFFFFF"
|
||||
python3 create_sw_versions.py logo.svg img/ol-brand/overleaf-o-grey.svg "#808080"
|
||||
|
||||
# 4. Generate standard icons (creates overleaf_og_logo.png)
|
||||
echo "Generating standard icons from logo.svg..."
|
||||
python3 generate_icons.py logo.svg
|
||||
|
||||
# 5. Generate additional logos (FIX: Moved up so logo-horizontal.png exists before copying)
|
||||
echo "Generating logo-horizontal.png from logo_full.svg..."
|
||||
python3 generate_additional_logos.py logo_full.svg logo-horizontal.png 410 180 --export-area-drawing
|
||||
|
||||
# 6. Final File Operations (Copying generated assets to destination)
|
||||
echo "Finalizing assets..."
|
||||
cp -f overleaf_og_logo.png img/ol-brand/
|
||||
cp -f logo-horizontal.png img/ol-brand/
|
||||
cp -f logo.svg img/ol-brand/overleaf-o.svg
|
||||
cp -f logo_full.svg img/ol-brand/overleaf.svg
|
||||
cp -f logo_full.svg img/ol-brand/overleaf-a-ds-solution-mallard.svg
|
||||
cp -f logo_full.svg img/ol-brand/overleaf-green.svg
|
||||
cp -f logo.svg img/ol-brand/overleaf-o-dark.svg
|
||||
|
||||
# 7. Inline Python for Dark Mallard Variant
|
||||
python3 - <<'PY'
|
||||
from pathlib import Path
|
||||
p = Path('img/ol-brand/overleaf-a-ds-solution-mallard.svg')
|
||||
out = Path('img/ol-brand/overleaf-a-ds-solution-mallard-dark.svg')
|
||||
if p.exists():
|
||||
s = p.read_text(encoding='utf-8')
|
||||
s = s.replace('#0000ff', '#FFFFFF').replace('#0000FF', '#FFFFFF')
|
||||
s = s.replace('#00aa00', '#13C965').replace('#00AA00', '#13C965')
|
||||
s = s.replace('fill:#0000ff', 'fill:#FFFFFF').replace('fill:#0000FF', 'fill:#FFFFFF')
|
||||
s = s.replace('stroke:#0000ff', 'stroke:#FFFFFF').replace('stroke:#0000FF', 'stroke:#FFFFFF')
|
||||
s = s.replace('fill:#00aa00', 'fill:#13C965').replace('fill:#00AA00', 'fill:#13C965')
|
||||
s = s.replace('stroke:#00aa00', 'stroke:#13C965').replace('stroke:#00AA00', 'stroke:#13C965')
|
||||
out.write_text(s, encoding='utf-8')
|
||||
print(f"✓ Created {out}")
|
||||
else:
|
||||
import sys
|
||||
print(f"✗ Reference mallard file not found: {p}")
|
||||
sys.exit(1)
|
||||
PY
|
||||
|
||||
echo ""
|
||||
echo "============================================================"
|
||||
echo "✓ All logos generated successfully!"
|
||||
echo "============================================================"
|
||||
16
tools/logo/2_install.sh
Executable file
16
tools/logo/2_install.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
cp -f *.png ../../services/web/public/
|
||||
cp -f *.svg ../../services/web/public/
|
||||
cp -f *.ico ../../services/web/public/
|
||||
|
||||
cp -f img/ol-brand/*.png ../../services/web/public/img/ol-brand/
|
||||
cp -f img/ol-brand/*.svg ../../services/web/public/img/ol-brand/
|
||||
|
||||
# Explicitly include the dark Mallard variant
|
||||
cp -f img/ol-brand/overleaf-a-ds-solution-mallard-dark.svg ../../services/web/public/img/ol-brand/
|
||||
|
||||
cp -f img/ol-brand/overleaf.svg ../../services/web/frontend/js/shared/svgs
|
||||
cp -f img/ol-brand/overleaf-*.svg ../../services/web/frontend/js/shared/svgs
|
||||
|
||||
# Explicitly copy the dark Mallard variant into shared svgs as well
|
||||
cp -f img/ol-brand/overleaf-a-ds-solution-mallard-dark.svg ../../services/web/frontend/js/shared/svgs
|
||||
|
||||
28
tools/logo/3_remove_branding_from_projectpage.sh
Executable file
28
tools/logo/3_remove_branding_from_projectpage.sh
Executable file
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Removes the ds-nav branding block from the project page sidebar component.
|
||||
# Usage: bash 3_remove_branding_from_projectpage.sh
|
||||
|
||||
TARGET="../../services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx"
|
||||
BACKUP="$TARGET.bak"
|
||||
|
||||
if [ ! -f "$TARGET" ]; then
|
||||
echo "ERROR: target file not found: $TARGET"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating backup: $BACKUP"
|
||||
cp -a "$TARGET" "$BACKUP"
|
||||
|
||||
# Use Perl to remove the <div ... className="ds-nav-ds-name" ...>...</div> block across multiple lines.
|
||||
# This will match regardless of attribute order or whitespace and removes the entire div including trailing newline.
|
||||
perl -0777 -pe "s#<div[^>]*className\\s*=\\s*[\'\"]ds-nav-ds-name[\'\"][^>]*>.*?</div>\\n?##gis" "$BACKUP" > "$TARGET"
|
||||
|
||||
if cmp -s "$TARGET" "$BACKUP"; then
|
||||
echo "No ds-nav-ds-name block found; no changes made."
|
||||
exit 0
|
||||
else
|
||||
echo "✓ Removed ds-nav-ds-name block from $TARGET"
|
||||
exit 0
|
||||
fi
|
||||
26
tools/logo/README.md
Normal file
26
tools/logo/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Overview
|
||||
|
||||
We assume that two files exist:
|
||||
|
||||
* logo.svg (short version of the logo)
|
||||
* logo_full.svg (wide version of the logo with e.g. University of Somewhere)
|
||||
|
||||
# 1_convert.sh
|
||||
|
||||
It does a lot of converting logos from one format to another and scales & changes colors of the logo for producing the required set of files.
|
||||
|
||||
In the moment it mainly uses inkscape and imagemagick as tools.
|
||||
|
||||
# 2_install.sh
|
||||
|
||||
This script copies the files to the correct positions before compilation. I seperated the scripts, since you may want to check the logos beforehand. Or do changes by hand.
|
||||
e.g. I don't like overleaf-a-ds-solution-mallard.svg as a long logo.
|
||||
|
||||
# 3_remove_branding_from_projectpage.sh
|
||||
|
||||
This script is a maintenance utility designed to modify the project list sidebar by removing specific branding elements from the frontend source code.
|
||||
|
||||
Target File: services/web/frontend/js/features/project-list/components/sidebar/sidebar-ds-nav.tsx
|
||||
|
||||
Action: Removes the <div ... className="ds-nav-ds-name" ...>...</div> block
|
||||
|
||||
74
tools/logo/check_dependency.py
Normal file
74
tools/logo/check_dependency.py
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Detected ImageMagick command (either 'magick' for IM v7 or 'convert' for IM v6)
|
||||
IMAGEMAGICK_CMD = None
|
||||
|
||||
def check_dependencies():
|
||||
"""Check if required tools are installed."""
|
||||
print("Checking dependencies...")
|
||||
|
||||
# Core dependency we always require
|
||||
dependencies = {
|
||||
"inkscape": "Inkscape (for PNG generation)"
|
||||
}
|
||||
|
||||
missing = []
|
||||
|
||||
# Check inkscape
|
||||
for cmd, description in dependencies.items():
|
||||
try:
|
||||
subprocess.run(
|
||||
[cmd, "--version"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
print(f" ✓ {description} - found")
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
print(f" ✗ {description} - NOT FOUND")
|
||||
missing.append(cmd)
|
||||
|
||||
# Detect ImageMagick: prefer 'magick' (ImageMagick 7), fall back to 'convert' (ImageMagick 6)
|
||||
global IMAGEMAGICK_CMD
|
||||
IMAGEMAGICK_CMD = None
|
||||
for cmd in ("magick", "convert"):
|
||||
try:
|
||||
subprocess.run([cmd, "--version"], check=True, capture_output=True, text=True)
|
||||
IMAGEMAGICK_CMD = cmd
|
||||
print(f" ✓ ImageMagick ({cmd}) - found")
|
||||
break
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
continue
|
||||
|
||||
if IMAGEMAGICK_CMD is None:
|
||||
print(f" ✗ ImageMagick - NOT FOUND (tried 'magick' and 'convert')")
|
||||
missing.append("ImageMagick ('magick' or 'convert')")
|
||||
|
||||
if missing:
|
||||
print(f"\n{'='*60}")
|
||||
print("ERROR: Missing required dependencies!")
|
||||
print(f"{'='*60}")
|
||||
print("\nThe following tools are required but not found:")
|
||||
for tool in missing:
|
||||
print(f" - {tool}")
|
||||
print("\nInstallation instructions:")
|
||||
print("\n Ubuntu/Debian:")
|
||||
print(" sudo apt install inkscape imagemagick")
|
||||
print("\n macOS:")
|
||||
print(" brew install inkscape imagemagick")
|
||||
print("\n Windows:")
|
||||
print(" Download from:")
|
||||
print(" - https://inkscape.org/")
|
||||
print(" - https://imagemagick.org/")
|
||||
print(f"{'='*60}\n")
|
||||
sys.exit(1)
|
||||
|
||||
print("✓ All dependencies found\n")
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_dependencies()
|
||||
178
tools/logo/create_sw_versions.py
Normal file
178
tools/logo/create_sw_versions.py
Normal file
@@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Create black/white versions of SVG logos.
|
||||
|
||||
This script converts all non-transparent and non-white colors to a specified color
|
||||
(default: black), creating modified versions of the logos.
|
||||
|
||||
Usage:
|
||||
python create_sw_versions.py <input.svg> <output.svg> [color]
|
||||
python create_sw_versions.py logo.svg logo_sw.svg
|
||||
python create_sw_versions.py logo.svg logo_sw.svg "#FF0000"
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def style_to_color(style_content, target_color):
|
||||
"""Convert colors in style attributes to target color."""
|
||||
# Replace fill colors
|
||||
style_content = re.sub(
|
||||
r'fill:\s*#[0-9a-fA-F]{6}',
|
||||
f'fill:{target_color}',
|
||||
style_content
|
||||
)
|
||||
style_content = re.sub(
|
||||
r'fill:\s*rgb\([^)]+\)',
|
||||
f'fill:{target_color}',
|
||||
style_content
|
||||
)
|
||||
|
||||
# Replace stroke colors
|
||||
style_content = re.sub(
|
||||
r'stroke:\s*#[0-9a-fA-F]{6}',
|
||||
f'stroke:{target_color}',
|
||||
style_content
|
||||
)
|
||||
style_content = re.sub(
|
||||
r'stroke:\s*rgb\([^)]+\)',
|
||||
f'stroke:{target_color}',
|
||||
style_content
|
||||
)
|
||||
|
||||
return style_content
|
||||
|
||||
|
||||
def convert_to_target_color(svg_content, target_color="#000000"):
|
||||
"""
|
||||
Convert SVG colors to target color, keeping transparent and white as-is.
|
||||
|
||||
Args:
|
||||
svg_content: String containing SVG XML content
|
||||
target_color: Target color (default: #000000 for black)
|
||||
|
||||
Returns:
|
||||
Modified SVG content with colors converted to target color
|
||||
"""
|
||||
# Handle fill and stroke attributes
|
||||
svg_content = re.sub(
|
||||
r'(fill|stroke)="(#(?!ffffff|FFFFFF|fff|FFF)[0-9a-fA-F]{6}|#(?!fff|FFF)[0-9a-fA-F]{3}|rgb\([^)]+\))"',
|
||||
rf'\1="{target_color}"',
|
||||
svg_content
|
||||
)
|
||||
|
||||
# Handle style attributes
|
||||
def replace_style(match):
|
||||
style_content = match.group(1)
|
||||
style_content = style_to_color(style_content, target_color)
|
||||
return f'style="{style_content}"'
|
||||
|
||||
svg_content = re.sub(
|
||||
r'style="([^"]+)"',
|
||||
replace_style,
|
||||
svg_content
|
||||
)
|
||||
|
||||
# Handle color attributes (less common)
|
||||
svg_content = re.sub(
|
||||
r'color="(#(?!ffffff|FFFFFF|fff|FFF)[0-9a-fA-F]{6}|rgb\([^)]+\))"',
|
||||
f'color="{target_color}"',
|
||||
svg_content
|
||||
)
|
||||
|
||||
return svg_content
|
||||
|
||||
|
||||
def process_svg_file(input_file, output_file, target_color="#000000"):
|
||||
"""
|
||||
Read SVG file, convert colors to target color, and save.
|
||||
|
||||
Args:
|
||||
input_file: Path to input SVG file
|
||||
output_file: Path to output SVG file
|
||||
target_color: Target color (default: #000000)
|
||||
"""
|
||||
try:
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
svg_content = f.read()
|
||||
|
||||
# Convert colors
|
||||
modified_content = convert_to_target_color(svg_content, target_color)
|
||||
|
||||
# Write output
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(modified_content)
|
||||
|
||||
print(f"✓ Created {output_file} with color {target_color}")
|
||||
return True
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"✗ Error: {input_file} not found")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"✗ Error processing {input_file}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
if len(sys.argv) < 3:
|
||||
print("=" * 60)
|
||||
print("ERROR: Invalid usage!")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print("Usage:")
|
||||
print(" python create_sw_versions.py <input.svg> <output.svg> [color]")
|
||||
print()
|
||||
print("Examples:")
|
||||
print(" python create_sw_versions.py logo.svg logo_sw.svg")
|
||||
print(" python create_sw_versions.py logo.svg logo_red.svg \"#FF0000\"")
|
||||
print(" python create_sw_versions.py logo_full.svg logo_full_sw.svg \"#000000\"")
|
||||
print()
|
||||
print("Default color: #000000 (black)")
|
||||
print("=" * 60)
|
||||
sys.exit(1)
|
||||
|
||||
input_file = sys.argv[1]
|
||||
output_file = sys.argv[2]
|
||||
target_color = sys.argv[3] if len(sys.argv) > 3 else "#000000"
|
||||
|
||||
# Check if input file exists
|
||||
if not os.path.isfile(input_file):
|
||||
print("=" * 60)
|
||||
print("ERROR: Input file not found!")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print(f"The file '{input_file}' does not exist.")
|
||||
print()
|
||||
print(f"Current directory: {os.getcwd()}")
|
||||
print("=" * 60)
|
||||
sys.exit(1)
|
||||
|
||||
# Validate color format
|
||||
if not re.match(r'^#[0-9a-fA-F]{6}$', target_color):
|
||||
print("=" * 60)
|
||||
print("WARNING: Invalid color format!")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print(f"Color '{target_color}' may not be valid.")
|
||||
print("Expected format: #RRGGBB (e.g., #000000, #FF0000)")
|
||||
print()
|
||||
print("Proceeding anyway...")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
print(f"Converting: {input_file} -> {output_file}")
|
||||
print(f"Target color: {target_color}")
|
||||
print()
|
||||
|
||||
if process_svg_file(input_file, output_file, target_color):
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
89
tools/logo/generate_additional_logos.py
Normal file
89
tools/logo/generate_additional_logos.py
Normal file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate logo PNG from SVG using Inkscape.
|
||||
|
||||
This script generates a PNG file from an SVG with specified dimensions and options.
|
||||
|
||||
Usage:
|
||||
python generate_additional_logos.py <input.svg> <output.png> <width> <height> [options]
|
||||
|
||||
Examples:
|
||||
python generate_additional_logos.py logo_full.svg logo-horizontal.png 410 180 --export-area-drawing
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
if len(sys.argv) < 5:
|
||||
print("=" * 60)
|
||||
print("ERROR: Invalid usage!")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print("Usage:")
|
||||
print(" python generate_additional_logos.py <input.svg> <output.png> <width> <height> [options]")
|
||||
print()
|
||||
print("Example:")
|
||||
print(" python generate_additional_logos.py logo_full.svg logo-horizontal.png 410 180 --export-area-drawing")
|
||||
print()
|
||||
print("Common options:")
|
||||
print(" --export-area-drawing Export the bounding box of all objects")
|
||||
print(" --export-area-page Export the page area (default)")
|
||||
print("=" * 60)
|
||||
sys.exit(1)
|
||||
|
||||
input_file = sys.argv[1]
|
||||
output_file = sys.argv[2]
|
||||
|
||||
# Parse dimensions
|
||||
try:
|
||||
width = int(sys.argv[3])
|
||||
height = int(sys.argv[4])
|
||||
except ValueError:
|
||||
print(f"ERROR: Invalid dimensions - width='{sys.argv[3]}', height='{sys.argv[4]}'")
|
||||
print("Width and height must be integers.")
|
||||
sys.exit(1)
|
||||
|
||||
# Check if input file exists
|
||||
if not os.path.isfile(input_file):
|
||||
print(f"ERROR: Input file '{input_file}' not found")
|
||||
print(f"Current directory: {os.getcwd()}")
|
||||
sys.exit(1)
|
||||
|
||||
# Build Inkscape command
|
||||
command = [
|
||||
"inkscape",
|
||||
f"--export-filename={output_file}",
|
||||
f"--export-width={width}",
|
||||
f"--export-height={height}",
|
||||
"--export-background-opacity=0"
|
||||
]
|
||||
|
||||
# Add extra options (e.g., --export-area-drawing)
|
||||
if len(sys.argv) > 5:
|
||||
command.extend(sys.argv[5:])
|
||||
|
||||
# Add input file
|
||||
command.append(input_file)
|
||||
|
||||
# Run Inkscape
|
||||
print(f"Generating {output_file} ({width}×{height}) from {input_file}")
|
||||
|
||||
try:
|
||||
subprocess.run(command, check=True, capture_output=True, text=True)
|
||||
print(f"✓ {output_file} created successfully")
|
||||
sys.exit(0)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"✗ Error: {e.stderr}")
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
print("✗ Error: Inkscape not found")
|
||||
print("Install: sudo apt install inkscape (or brew install inkscape)")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
144
tools/logo/generate_favicons.py
Normal file
144
tools/logo/generate_favicons.py
Normal file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate favicon variants with status indicators (compiled, compiling, error)
|
||||
Usage: python generate_favicons.py favicon.svg
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
def create_compiled_icon(size):
|
||||
"""Create a green checkmark icon"""
|
||||
circle = f'<circle cx="{size/2}" cy="{size/2}" r="{size/2}" fill="#22c55e"/>'
|
||||
check_path = f'<path d="M {size*0.25} {size*0.5} L {size*0.4} {size*0.65} L {size*0.75} {size*0.3}" stroke="white" stroke-width="{size*0.15}" fill="none" stroke-linecap="round" stroke-linejoin="round"/>'
|
||||
return f'{circle}{check_path}'
|
||||
|
||||
def create_compiling_icon(size):
|
||||
"""Create rotating arrows icon (circular progress)"""
|
||||
circle = f'<circle cx="{size/2}" cy="{size/2}" r="{size/2}" fill="#e5e7eb"/>'
|
||||
r = size * 0.3
|
||||
cx, cy = size/2, size/2
|
||||
stroke_w = size * 0.06
|
||||
arrow_len = stroke_w * 2
|
||||
|
||||
# Two SHORT arcs with arrow heads, forming an open circle
|
||||
# Arc 1: short arc at top-right (about 90 degrees)
|
||||
arc1 = f'<path d="M {cx} {cy-r} A {r} {r} 0 0 1 {cx+r} {cy}" stroke="black" stroke-width="{stroke_w}" fill="none" stroke-linecap="round"/>'
|
||||
# Arrow head for arc1 (pointing downward/clockwise at right side)
|
||||
arrow1 = f'<path d="M {cx+r-arrow_len} {cy-arrow_len} L {cx+r} {cy} L {cx+r+arrow_len} {cy-arrow_len}" stroke="black" stroke-width="{stroke_w}" fill="none" stroke-linecap="round" stroke-linejoin="round"/>'
|
||||
|
||||
# Arc 2: short arc at bottom-left (about 90 degrees)
|
||||
arc2 = f'<path d="M {cx} {cy+r} A {r} {r} 0 0 1 {cx-r} {cy}" stroke="black" stroke-width="{stroke_w}" fill="none" stroke-linecap="round"/>'
|
||||
# Arrow head for arc2 (pointing upward/clockwise at left side)
|
||||
arrow2 = f'<path d="M {cx-r-arrow_len} {cy+arrow_len} L {cx-r} {cy} L {cx-r+arrow_len} {cy+arrow_len}" stroke="black" stroke-width="{stroke_w}" fill="none" stroke-linecap="round" stroke-linejoin="round"/>'
|
||||
|
||||
return f'{circle}{arc1}{arrow1}{arc2}{arrow2}'
|
||||
|
||||
def create_error_icon(size):
|
||||
"""Create a red X icon"""
|
||||
circle = f'<circle cx="{size/2}" cy="{size/2}" r="{size/2}" fill="#ef4444"/>'
|
||||
x1 = f'<line x1="{size*0.3}" y1="{size*0.3}" x2="{size*0.7}" y2="{size*0.7}" stroke="white" stroke-width="{size*0.15}" stroke-linecap="round"/>'
|
||||
x2 = f'<line x1="{size*0.7}" y1="{size*0.3}" x2="{size*0.3}" y2="{size*0.7}" stroke="white" stroke-width="{size*0.15}" stroke-linecap="round"/>'
|
||||
return f'{circle}{x1}{x2}'
|
||||
|
||||
def extract_dimensions(svg_content):
|
||||
"""Extract width and height from SVG content"""
|
||||
# Try to find viewBox
|
||||
if 'viewBox=' in svg_content:
|
||||
start = svg_content.find('viewBox=')
|
||||
quote = svg_content[start + 8]
|
||||
start = start + 9
|
||||
end = svg_content.find(quote, start)
|
||||
viewbox = svg_content[start:end]
|
||||
parts = viewbox.split()
|
||||
return float(parts[2]), float(parts[3])
|
||||
|
||||
# Try to find width and height attributes
|
||||
width = 100
|
||||
height = 100
|
||||
if 'width=' in svg_content:
|
||||
start = svg_content.find('width=')
|
||||
quote = svg_content[start + 6]
|
||||
start = start + 7
|
||||
end = svg_content.find(quote, start)
|
||||
width = float(svg_content[start:end].replace('px', ''))
|
||||
|
||||
if 'height=' in svg_content:
|
||||
start = svg_content.find('height=')
|
||||
quote = svg_content[start + 7]
|
||||
start = start + 8
|
||||
end = svg_content.find(quote, start)
|
||||
height = float(svg_content[start:end].replace('px', ''))
|
||||
|
||||
return width, height
|
||||
|
||||
def add_overlay_to_svg(input_file, output_file, overlay_creator):
|
||||
"""Add an overlay icon to the SVG in the lower right corner"""
|
||||
with open(input_file, 'r') as f:
|
||||
svg_content = f.read()
|
||||
|
||||
# Extract dimensions
|
||||
width, height = extract_dimensions(svg_content)
|
||||
|
||||
# Calculate overlay size and position (1/3 of the icon size)
|
||||
overlay_size = min(width, height) / 3
|
||||
overlay_x = width - overlay_size - (overlay_size * 0.1)
|
||||
overlay_y = height - overlay_size - (overlay_size * 0.1)
|
||||
|
||||
# Create overlay group
|
||||
overlay_svg = f'<g transform="translate({overlay_x}, {overlay_y})">\n {overlay_creator(overlay_size)}\n</g>'
|
||||
|
||||
# Find the closing </svg> tag and insert overlay before it
|
||||
closing_tag = '</svg>'
|
||||
insert_pos = svg_content.rfind(closing_tag)
|
||||
|
||||
if insert_pos == -1:
|
||||
print(f"Error: Could not find closing </svg> tag in {input_file}")
|
||||
return
|
||||
|
||||
# Insert the overlay
|
||||
new_content = svg_content[:insert_pos] + overlay_svg + '\n' + svg_content[insert_pos:]
|
||||
|
||||
# Write output
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(new_content)
|
||||
|
||||
print(f"Created: {output_file}")
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
print("Usage: python generate_favicons.py favicon.svg")
|
||||
sys.exit(1)
|
||||
|
||||
input_file = Path(sys.argv[1])
|
||||
|
||||
if not input_file.exists():
|
||||
print(f"Error: {input_file} not found")
|
||||
sys.exit(1)
|
||||
|
||||
base_name = input_file.stem
|
||||
output_dir = input_file.parent
|
||||
|
||||
# Generate the three variants
|
||||
add_overlay_to_svg(
|
||||
input_file,
|
||||
output_dir / f"{base_name}-compiled.svg",
|
||||
create_compiled_icon
|
||||
)
|
||||
|
||||
add_overlay_to_svg(
|
||||
input_file,
|
||||
output_dir / f"{base_name}-compiling.svg",
|
||||
create_compiling_icon
|
||||
)
|
||||
|
||||
add_overlay_to_svg(
|
||||
input_file,
|
||||
output_dir / f"{base_name}-error.svg",
|
||||
create_error_icon
|
||||
)
|
||||
|
||||
print("\nAll favicon variants created successfully!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
241
tools/logo/generate_icons.py
Normal file
241
tools/logo/generate_icons.py
Normal file
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Icon Generator Tool
|
||||
|
||||
This script generates various icon sizes from an SVG file using Inkscape,
|
||||
and creates a favicon.ico file using ImageMagick.
|
||||
|
||||
Usage:
|
||||
python generate_icons.py <input_svg_file>
|
||||
python generate_icons.py logo.svg
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
# Detected ImageMagick command (either 'magick' for IM v7 or 'convert' for IM v6)
|
||||
IMAGEMAGICK_CMD = None
|
||||
|
||||
|
||||
def run_command(command, description):
|
||||
"""
|
||||
Execute a shell command and handle errors.
|
||||
|
||||
Args:
|
||||
command: List of command arguments
|
||||
description: Human-readable description of the command
|
||||
"""
|
||||
print(f"Running: {description}")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
print(f"✓ {description} completed successfully")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"✗ Error during {description}:")
|
||||
print(f" {e.stderr}")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
print(f"✗ Error: Required tool not found for {description}")
|
||||
print(f" Make sure the command '{command[0]}' is installed and in your PATH")
|
||||
return False
|
||||
|
||||
|
||||
def check_file_exists(filepath):
|
||||
"""Check if a file exists."""
|
||||
if not os.path.isfile(filepath):
|
||||
print(f"\n{'='*60}")
|
||||
print("ERROR: Input file not found!")
|
||||
print(f"{'='*60}")
|
||||
print(f"\nThe file '{filepath}' does not exist.\n")
|
||||
print("Requirements:")
|
||||
print(f" 1. Create or place '{filepath}' in the current directory")
|
||||
print(f" 2. Ensure the file is a valid SVG file")
|
||||
print(f"\nCurrent directory: {os.getcwd()}")
|
||||
print(f"{'='*60}\n")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def check_dependencies():
|
||||
"""Check if required tools are installed."""
|
||||
print("Checking dependencies...")
|
||||
|
||||
# Core dependency we always require
|
||||
dependencies = {
|
||||
"inkscape": "Inkscape (for PNG generation)"
|
||||
}
|
||||
|
||||
missing = []
|
||||
|
||||
# Check inkscape
|
||||
for cmd, description in dependencies.items():
|
||||
try:
|
||||
subprocess.run(
|
||||
[cmd, "--version"],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
print(f" ✓ {description} - found")
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
print(f" ✗ {description} - NOT FOUND")
|
||||
missing.append(cmd)
|
||||
|
||||
# Detect ImageMagick: prefer 'magick' (ImageMagick 7), fall back to 'convert' (ImageMagick 6)
|
||||
global IMAGEMAGICK_CMD
|
||||
IMAGEMAGICK_CMD = None
|
||||
for cmd in ("magick", "convert"):
|
||||
try:
|
||||
subprocess.run([cmd, "--version"], check=True, capture_output=True, text=True)
|
||||
IMAGEMAGICK_CMD = cmd
|
||||
print(f" ✓ ImageMagick ({cmd}) - found")
|
||||
break
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
continue
|
||||
|
||||
if IMAGEMAGICK_CMD is None:
|
||||
print(f" ✗ ImageMagick - NOT FOUND (tried 'magick' and 'convert')")
|
||||
missing.append("ImageMagick ('magick' or 'convert')")
|
||||
|
||||
if missing:
|
||||
print(f"\n{'='*60}")
|
||||
print("ERROR: Missing required dependencies!")
|
||||
print(f"{'='*60}")
|
||||
print("\nThe following tools are required but not found:")
|
||||
for tool in missing:
|
||||
print(f" - {tool}")
|
||||
print("\nInstallation instructions:")
|
||||
print("\n Ubuntu/Debian:")
|
||||
print(" sudo apt install inkscape imagemagick")
|
||||
print("\n macOS:")
|
||||
print(" brew install inkscape imagemagick")
|
||||
print("\n Windows:")
|
||||
print(" Download from:")
|
||||
print(" - https://inkscape.org/")
|
||||
print(" - https://imagemagick.org/")
|
||||
print(f"{'='*60}\n")
|
||||
return False
|
||||
|
||||
print("✓ All dependencies found\n")
|
||||
return True
|
||||
|
||||
|
||||
def generate_icons(svg_file):
|
||||
"""
|
||||
Generate all icon sizes from an SVG file.
|
||||
|
||||
Args:
|
||||
svg_file: Path to the input SVG file
|
||||
"""
|
||||
print(f"Generating icons from: {svg_file}\n")
|
||||
|
||||
# Define icon configurations
|
||||
# Format: (filename, width, height, background)
|
||||
icons = [
|
||||
("android-chrome-512x512.png", 512, 512, "--export-background-opacity=0"),
|
||||
("android-chrome-192x192.png", 192, 192, "--export-background-opacity=0"),
|
||||
("apple-touch-icon.png", 180, 180, "--export-background=#FFFFFF"),
|
||||
("favicon-16x16.png", 16, 16, "--export-background-opacity=0"),
|
||||
("favicon-32x32.png", 32, 32, "--export-background-opacity=0"),
|
||||
("overleaf_og_logo.png", 256, 256, "--export-background-opacity=0"),
|
||||
]
|
||||
|
||||
success_count = 0
|
||||
|
||||
# Generate PNG files using Inkscape
|
||||
for filename, width, height, background in icons:
|
||||
command = [
|
||||
"inkscape",
|
||||
f"--export-filename={filename}",
|
||||
f"--export-width={width}",
|
||||
f"--export-height={height}",
|
||||
background,
|
||||
svg_file
|
||||
]
|
||||
|
||||
if run_command(command, f"Generating {filename}"):
|
||||
success_count += 1
|
||||
else:
|
||||
print(f"Warning: Failed to generate {filename}")
|
||||
|
||||
print(f"\n{success_count}/{len(icons)} PNG icons generated successfully\n")
|
||||
|
||||
# Generate favicon.ico using ImageMagick
|
||||
if check_file_exists("favicon-32x32.png"):
|
||||
if IMAGEMAGICK_CMD is None:
|
||||
print("\n✗ Cannot generate favicon.ico: no ImageMagick command detected")
|
||||
return False
|
||||
|
||||
command = [
|
||||
IMAGEMAGICK_CMD,
|
||||
"favicon-32x32.png",
|
||||
"favicon.ico"
|
||||
]
|
||||
|
||||
if run_command(command, "Generating favicon.ico"):
|
||||
print("\n✓ All icons generated successfully!")
|
||||
return True
|
||||
else:
|
||||
print("\nWarning: PNG icons generated, but favicon.ico creation failed")
|
||||
return False
|
||||
else:
|
||||
print("\n✗ Cannot generate favicon.ico: favicon-32x32.png not found")
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
if len(sys.argv) != 2:
|
||||
print(f"\n{'='*60}")
|
||||
print("ERROR: Invalid usage!")
|
||||
print(f"{'='*60}")
|
||||
print("\nUsage: python generate_icons.py <input_svg_file>")
|
||||
print("\nExample:")
|
||||
print(" python generate_icons.py logo.svg")
|
||||
print(f"{'='*60}\n")
|
||||
sys.exit(1)
|
||||
|
||||
svg_file = sys.argv[1]
|
||||
|
||||
print("=" * 60)
|
||||
print("Icon Generator Tool")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
# Check if input file exists FIRST
|
||||
if not check_file_exists(svg_file):
|
||||
sys.exit(1)
|
||||
|
||||
# Check if required tools are installed
|
||||
if not check_dependencies():
|
||||
sys.exit(1)
|
||||
|
||||
# Proceed with icon generation
|
||||
success = generate_icons(svg_file)
|
||||
|
||||
print("=" * 60)
|
||||
|
||||
if success:
|
||||
print("\nGenerated files:")
|
||||
print(" - android-chrome-512x512.png (512×512, transparent)")
|
||||
print(" - android-chrome-192x192.png (192×192, transparent)")
|
||||
print(" - apple-touch-icon.png (180×180, white background)")
|
||||
print(" - favicon-16x16.png (16×16, transparent)")
|
||||
print(" - favicon-32x32.png (32×32, transparent)")
|
||||
print(" - overleaf_og_logo.png (256×256, transparent)")
|
||||
print(" - favicon.ico")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("\n✗ Icon generation completed with errors")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
61
tools/logo/logo.svg
Normal file
61
tools/logo/logo.svg
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
width="59.52"
|
||||
height="54.080002"
|
||||
viewBox="0 0 59.52 54.080002"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect1"
|
||||
width="10.99932"
|
||||
height="1.8332207"
|
||||
x="17.017767"
|
||||
y="9.9218159" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect2"
|
||||
width="2.2915268"
|
||||
height="31.426634"
|
||||
x="25.720428"
|
||||
y="12.745403" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect3"
|
||||
width="2.2915268"
|
||||
height="31.426634"
|
||||
x="31.764208"
|
||||
y="12.714312" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect4"
|
||||
width="10.99932"
|
||||
height="1.8332207"
|
||||
x="31.768179"
|
||||
y="9.8910656" />
|
||||
<path
|
||||
d="m 7.6602438,29.399278 q 0,-1.327712 -0.8153199,-2.141471 -0.79134,-0.835175 -2.3260598,-0.835175 v -2.248544 q 1.5347198,0 2.3260598,-0.813759 0.8153199,-0.835174 0.8153199,-2.141471 0,-1.049321 -0.19184,-2.055812 -0.1678599,-1.027906 -0.40766,-2.034398 -0.2158199,-1.006491 -0.4076599,-2.034398 -0.16786,-1.027906 -0.16786,-2.098642 0,-1.434785 0.4796,-2.634009 0.4795999,-1.1992239 1.4387999,-2.0558124 0.9831798,-0.8780032 2.3979992,-1.3491269 1.4388,-0.4925383 3.3572,-0.4925383 h 1.24696 V 8.134469 q 0,0.4282941 -0.33572,0.6210266 -0.33572,0.1713177 -0.5995,0.1713177 h -0.45562 q -1.7985,0 -2.829639,1.0493208 -1.00716,1.0279059 -1.00716,2.8053279 0,1.156394 0.16786,2.227129 0.167859,1.070736 0.3597,2.098642 0.19184,1.027907 0.359699,2.034398 0.167861,0.985077 0.167861,2.012983 0,0.77093 -0.26378,1.4562 -0.26378,0.663856 -0.719401,1.220638 -0.4556194,0.535368 -1.1030793,0.920833 -0.64746,0.36405 -1.3908399,0.556783 0.7433799,0.192732 1.3908399,0.578197 0.6474599,0.36405 1.1030793,0.920833 0.455621,0.535367 0.719401,1.199224 0.26378,0.663855 0.26378,1.434785 0,1.027906 -0.167861,2.034397 -0.167859,1.006492 -0.359699,2.034398 -0.191841,1.027906 -0.3597,2.098643 -0.16786,1.070735 -0.16786,2.227129 0,1.756006 1.00716,2.783912 1.031139,1.049321 2.829639,1.049321 h 0.45562 q 0.26378,0 0.5995,0.171318 0.33572,0.192733 0.33572,0.621027 v 1.670347 h -1.24696 q -1.9184,0 -3.3572,-0.492538 -1.4148194,-0.471124 -2.3979992,-1.349127 -0.9592,-0.856589 -1.4387999,-2.055812 -0.4796,-1.199224 -0.4796,-2.63401 0,-1.070735 0.16786,-2.098642 0.19184,-1.027906 0.4076599,-2.034397 0.2398001,-1.006492 0.40766,-2.012983 0.19184,-1.027906 0.19184,-2.055812 z"
|
||||
id="text6"
|
||||
style="font-size:46.4099px;font-family:Carlito;-inkscape-font-specification:'Carlito, Normal';fill:#0000ff;stroke:#0000ff;stroke-width:0.101133"
|
||||
aria-label="{" />
|
||||
<path
|
||||
d="m 52.078797,21.290035 c 0,0.885141 0.271773,1.598965 0.81532,2.14147 0.52756,0.556783 1.302913,0.835175 2.32606,0.835175 v 2.248544 c -1.023147,0 -1.7985,0.271253 -2.32606,0.81376 -0.543547,0.556782 -0.81532,1.270605 -0.81532,2.14147 0,0.699547 0.06395,1.384818 0.19184,2.055813 0.111907,0.685271 0.247793,1.363403 0.40766,2.034397 0.14388,0.670995 0.279767,1.349127 0.40766,2.034398 0.111907,0.685271 0.16786,1.384818 0.16786,2.098642 0,0.956524 -0.159867,1.834527 -0.4796,2.634009 -0.319733,0.799483 -0.581985,2.085727 -1.4388,2.055813 -3.145619,-0.109822 -2.751636,-1.509052 -2.78168,-1.670348 0.671441,-0.685271 1.007161,-1.62038 1.007161,-2.805327 0,-0.770929 -0.05595,-1.513306 -0.167861,-2.22713 -0.111906,-0.713824 -0.231806,-1.413371 -0.3597,-2.098642 -0.127893,-0.685271 -0.247793,-1.363403 -0.359699,-2.034398 -0.111907,-0.656718 -0.167861,-1.327712 -0.167861,-2.012983 0,-0.513953 0.08793,-0.999352 0.26378,-1.456199 0.175853,-0.442571 0.415654,-0.849451 0.719401,-1.220639 0.303747,-0.356912 0.67144,-0.663856 1.103079,-0.920833 0.43164,-0.2427 0.895253,-0.428294 1.39084,-0.556782 -0.495587,-0.128489 -0.9592,-0.321221 -1.39084,-0.578197 -0.431639,-0.242701 -0.799332,-0.549645 -1.103079,-0.920833 -0.303747,-0.356912 -0.543548,-0.756653 -0.719401,-1.199224 -0.175853,-0.442571 -0.26378,-0.920833 -0.26378,-1.434786 0,-0.685271 0.05595,-1.363403 0.167861,-2.034397 0.111906,-0.670995 0.231806,-1.349127 0.359699,-2.034398 0.127894,-0.685271 0.247794,-1.384818 0.3597,-2.098642 0.111907,-0.713824 0.167861,-1.456201 0.167861,-2.22713 0,-1.170671 -0.33572,-2.098641 -1.007161,-2.783912 C 47.866311,9.3691787 46.923098,9.019405 45.724098,9.019405 h -0.45562 c -0.175853,0 -0.375687,-0.057106 -0.5995,-0.171318 C 44.445165,8.719599 44.333258,8.51259 44.333258,8.22706 V 6.5567131 h 1.24696 c 1.278933,0 2.398,0.1641793 3.3572,0.4925379 0.943213,0.3140827 1.742546,0.7637917 2.397999,1.349127 0.639467,0.5710593 1.119067,1.25633 1.4388,2.055812 0.319733,0.799483 0.4796,1.677486 0.4796,2.63401 0,0.713824 -0.05595,1.413371 -0.16786,2.098642 -0.127893,0.685271 -0.26378,1.363403 -0.40766,2.034398 -0.159867,0.670994 -0.295753,1.341988 -0.40766,2.012982 -0.127893,0.685271 -0.19184,1.370542 -0.19184,2.055813 z"
|
||||
id="path7"
|
||||
style="font-size:46.4099px;font-family:Carlito;-inkscape-font-specification:'Carlito, Normal';fill:#0000ff;stroke:#0000ff;stroke-width:0.101133"
|
||||
aria-label="{" />
|
||||
<path
|
||||
d="m 43.15455,39.746636 9.084315,9.539497 -2.316961,2.002922 -8.117171,-10.368577 -2.978375,3.75192 -0.278753,-8.872599 8.719417,1.520361 z"
|
||||
id="text7"
|
||||
style="font-size:22.9019px;font-family:Carlito;-inkscape-font-specification:'Carlito, Normal';fill:#00aa00;stroke:#00aa00;stroke-width:0.0570312"
|
||||
aria-label="➚" />
|
||||
<path
|
||||
id="rect10"
|
||||
style="fill:#00aa00;stroke:#00aa00"
|
||||
d="M 9.6996531,45.462482 H 14.514417 L 12.288364,47.712599 9.6996531,50.46243 Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
66
tools/logo/logo_full.svg
Normal file
66
tools/logo/logo_full.svg
Normal file
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
width="144.80148"
|
||||
height="45.887009"
|
||||
viewBox="0 0 144.80148 45.887009"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect1"
|
||||
width="10.99932"
|
||||
height="1.8332207"
|
||||
x="12.549469"
|
||||
y="4.0858331" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect2"
|
||||
width="2.2915268"
|
||||
height="31.426634"
|
||||
x="21.252131"
|
||||
y="6.9094205" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect3"
|
||||
width="2.2915268"
|
||||
height="31.426634"
|
||||
x="27.29591"
|
||||
y="6.8783288" />
|
||||
<rect
|
||||
style="fill:#0000ff;stroke:#0000ff"
|
||||
id="rect4"
|
||||
width="10.99932"
|
||||
height="1.8332207"
|
||||
x="27.299881"
|
||||
y="4.0550828" />
|
||||
<path
|
||||
d="m 3.1919462,23.563295 q 0,-1.327712 -0.8153199,-2.141471 -0.79134,-0.835175 -2.32605978,-0.835175 v -2.248544 q 1.53471978,0 2.32605978,-0.813759 0.8153199,-0.835174 0.8153199,-2.141471 0,-1.049321 -0.19184,-2.055812 -0.1678599,-1.027906 -0.40766,-2.034398 -0.2158199,-1.006491 -0.4076599,-2.0343978 -0.16786,-1.027906 -0.16786,-2.098642 0,-1.434785 0.4796,-2.634009 Q 2.9761262,3.3263923 3.9353262,2.4698038 4.918506,1.5918006 6.3333254,1.1206769 q 1.4388,-0.49253826 3.3572,-0.49253826 H 10.937485 V 2.2984862 q 0,0.4282941 -0.33572,0.6210266 -0.33572,0.1713177 -0.5995,0.1713177 H 9.5466454 q -1.7985,0 -2.829639,1.0493208 -1.00716,1.0279059 -1.00716,2.8053279 0,1.156394 0.16786,2.227129 0.167859,1.0707358 0.3597,2.0986418 0.19184,1.027907 0.359699,2.034398 0.167861,0.985077 0.167861,2.012983 0,0.77093 -0.26378,1.4562 -0.26378,0.663856 -0.719401,1.220638 -0.4556194,0.535368 -1.1030793,0.920833 -0.64746,0.36405 -1.3908399,0.556783 0.7433799,0.192732 1.3908399,0.578197 0.6474599,0.36405 1.1030793,0.920833 0.455621,0.535367 0.719401,1.199224 0.26378,0.663855 0.26378,1.434785 0,1.027906 -0.167861,2.034397 -0.167859,1.006492 -0.359699,2.034398 -0.191841,1.027906 -0.3597,2.098643 -0.16786,1.070735 -0.16786,2.227129 0,1.756006 1.00716,2.783912 1.031139,1.049321 2.829639,1.049321 h 0.4556196 q 0.26378,0 0.5995,0.171318 0.33572,0.192733 0.33572,0.621027 v 1.670347 H 9.6905254 q -1.9184,0 -3.3572,-0.492538 -1.4148194,-0.471124 -2.3979992,-1.349127 -0.9592,-0.856589 -1.4387999,-2.055812 -0.4796,-1.199224 -0.4796,-2.63401 0,-1.070735 0.16786,-2.098642 0.19184,-1.027906 0.4076599,-2.034397 0.2398001,-1.006492 0.40766,-2.012983 0.19184,-1.027906 0.19184,-2.055812 z"
|
||||
id="text6"
|
||||
style="font-size:46.4099px;font-family:Carlito;-inkscape-font-specification:'Carlito, Normal';fill:#0000ff;stroke:#0000ff;stroke-width:0.101133"
|
||||
aria-label="{" />
|
||||
<path
|
||||
d="m 47.610499,15.454052 c 0,0.885141 0.271773,1.598965 0.81532,2.14147 0.52756,0.556783 1.302913,0.835175 2.32606,0.835175 v 2.248544 c -1.023147,0 -1.7985,0.271253 -2.32606,0.81376 -0.543547,0.556782 -0.81532,1.270605 -0.81532,2.14147 0,0.699547 0.06395,1.384818 0.19184,2.055813 0.111907,0.685271 0.247793,1.363403 0.40766,2.034397 0.14388,0.670995 0.279767,1.349127 0.40766,2.034398 0.111907,0.685271 0.16786,1.384818 0.16786,2.098642 0,0.956524 -0.159867,1.834527 -0.4796,2.634009 -0.319733,0.799483 -0.581985,2.085727 -1.4388,2.055813 -3.145619,-0.109822 -2.751636,-1.509052 -2.78168,-1.670348 0.671441,-0.685271 1.007161,-1.62038 1.007161,-2.805327 0,-0.770929 -0.05595,-1.513306 -0.167861,-2.22713 -0.111906,-0.713824 -0.231806,-1.413371 -0.3597,-2.098642 -0.127893,-0.685271 -0.247793,-1.363403 -0.359699,-2.034398 -0.111907,-0.656718 -0.167861,-1.327712 -0.167861,-2.012983 0,-0.513953 0.08793,-0.999352 0.26378,-1.456199 0.175853,-0.442571 0.415654,-0.849451 0.719401,-1.220639 0.303747,-0.356912 0.67144,-0.663856 1.103079,-0.920833 0.43164,-0.2427 0.895253,-0.428294 1.39084,-0.556782 -0.495587,-0.128489 -0.9592,-0.321221 -1.39084,-0.578197 C 45.6921,18.723364 45.324407,18.41642 45.02066,18.045232 44.716913,17.68832 44.477112,17.288579 44.301259,16.846008 c -0.175853,-0.442571 -0.26378,-0.920833 -0.26378,-1.434786 0,-0.685271 0.05595,-1.363403 0.167861,-2.034397 0.111906,-0.670995 0.231806,-1.349127 0.359699,-2.034398 0.127894,-0.685271 0.247794,-1.3848178 0.3597,-2.0986418 0.111907,-0.713824 0.167861,-1.456201 0.167861,-2.22713 0,-1.170671 -0.33572,-2.098641 -1.007161,-2.783912 C 43.398013,3.5331959 42.4548,3.1834222 41.2558,3.1834222 h -0.45562 c -0.175853,0 -0.375687,-0.057106 -0.5995,-0.171318 -0.223813,-0.128488 -0.33572,-0.335497 -0.33572,-0.621027 V 0.72073034 h 1.24696 c 1.278933,0 2.398,0.1641793 3.3572,0.49253786 0.943213,0.3140827 1.742546,0.7637917 2.397999,1.349127 0.639467,0.5710593 1.119067,1.25633 1.4388,2.055812 0.319733,0.799483 0.4796,1.677486 0.4796,2.63401 0,0.713824 -0.05595,1.413371 -0.16786,2.098642 -0.127893,0.6852708 -0.26378,1.3634028 -0.40766,2.0343978 -0.159867,0.670994 -0.295753,1.341988 -0.40766,2.012982 -0.127893,0.685271 -0.19184,1.370542 -0.19184,2.055813 z"
|
||||
id="path7"
|
||||
style="font-size:46.4099px;font-family:Carlito;-inkscape-font-specification:'Carlito, Normal';fill:#0000ff;stroke:#0000ff;stroke-width:0.101133"
|
||||
aria-label="{" />
|
||||
<path
|
||||
d="m 38.686252,33.910653 9.084315,9.539497 -2.316961,2.002922 -8.117171,-10.368577 -2.978375,3.75192 -0.278753,-8.872599 8.719417,1.520361 z"
|
||||
id="text7"
|
||||
style="font-size:22.9019px;font-family:Carlito;-inkscape-font-specification:'Carlito, Normal';fill:#00aa00;stroke:#00aa00;stroke-width:0.0570312"
|
||||
aria-label="➚" />
|
||||
<path
|
||||
id="rect10"
|
||||
style="fill:#00aa00;stroke:#00aa00"
|
||||
d="M 5.2313555,39.626499 H 10.046119 L 7.8200664,41.876616 5.2313555,44.626447 Z" />
|
||||
<path
|
||||
d="m 84.710592,4.5651461 v 5.0329993 q -2.338345,-2.2447652 -4.99764,-3.3553329 -2.63637,-1.1105687 -5.616613,-1.1105687 -5.868788,0 -8.986582,3.70977 -3.117793,3.6861402 -3.117793,10.6803552 0,6.970585 3.117793,10.680355 3.117794,3.686141 8.986582,3.686141 2.980243,0 5.616613,-1.110569 2.659295,-1.110568 4.99764,-3.355333 v 4.985742 q -2.430046,1.701295 -5.158114,2.551943 -2.705145,0.850647 -5.731239,0.850647 -7.771559,0 -12.241925,-4.891224 -4.470365,-4.914853 -4.470365,-13.397702 0,-8.506477 4.470365,-13.3977022 4.470366,-4.9148539 12.241925,-4.9148539 3.071943,0 5.777089,0.8506478 2.728069,0.8270186 5.112264,2.5046854 z m 7.152587,-2.7173474 h 21.641151 v 4.016948 H 96.494015 V 16.30881 h 16.299645 v 4.016949 H 96.494015 v 12.783345 h 17.422965 v 4.016948 H 91.863179 Z m 34.295731,3.922431 V 19.026158 h 5.82293 q 3.23243,0 4.99765,-1.724925 1.76522,-1.724925 1.76522,-4.914853 0,-3.1663004 -1.76522,-4.8912253 -1.76522,-1.724925 -4.99765,-1.724925 z m -4.63084,-3.922431 h 10.45377 q 5.75417,0 8.68857,2.6937176 2.95731,2.6700895 2.95731,7.8448637 0,5.222032 -2.95731,7.89212 -2.9344,2.670089 -8.68857,2.670089 h -5.82293 v 14.177463 h -4.63084 z"
|
||||
id="text1"
|
||||
style="font-size:47.6659px;line-height:125%;font-family:'Bitstream Vera Sans';letter-spacing:0px;word-spacing:0px;fill:#0000ff;stroke:#0000ff;stroke-width:2.3833px"
|
||||
aria-label="CEP" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
Reference in New Issue
Block a user