mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-23 09:09:36 +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