diff --git a/resources/branding/generate-splash.py b/resources/branding/generate-splash.py index 7df5e67109..8cd2ee8533 100755 --- a/resources/branding/generate-splash.py +++ b/resources/branding/generate-splash.py @@ -34,53 +34,67 @@ except ImportError: # Catppuccin Mocha colors COLORS = { - 'base': '#1e1e2e', - 'surface0': '#313244', - 'text': '#cdd6f4', - 'subtext0': '#a6adc8', - 'blue': '#89b4fa', - 'lavender': '#b4befe', + "mantle": "#181825", + "base": "#1e1e2e", + "surface0": "#313244", + "text": "#cdd6f4", + "subtext0": "#a6adc8", + "blue": "#89b4fa", + "lavender": "#b4befe", } + def hex_to_rgb(hex_color): """Convert hex color to RGB tuple.""" - hex_color = hex_color.lstrip('#') - return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)) + hex_color = hex_color.lstrip("#") + return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4)) + def create_rounded_rectangle(draw, bbox, radius, fill): """Draw a rounded rectangle.""" x1, y1, x2, y2 = bbox draw.rounded_rectangle(bbox, radius=radius, fill=fill) + def load_svg_as_image(svg_path, width, height): """Load an SVG file and convert to PIL Image at specified size.""" if cairosvg: import io + png_data = cairosvg.svg2png(url=str(svg_path), output_width=width, output_height=height) - return Image.open(io.BytesIO(png_data)).convert('RGBA') + return Image.open(io.BytesIO(png_data)).convert("RGBA") else: # Fallback: try using inkscape command line import subprocess import tempfile - with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp: + + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp: tmp_path = tmp.name try: - subprocess.run([ - 'inkscape', '-w', str(width), '-h', str(height), - str(svg_path), '-o', tmp_path - ], check=True, capture_output=True) - img = Image.open(tmp_path).convert('RGBA') + subprocess.run( + ["inkscape", "-w", str(width), "-h", str(height), str(svg_path), "-o", tmp_path], + check=True, + capture_output=True, + ) + img = Image.open(tmp_path).convert("RGBA") return img finally: if os.path.exists(tmp_path): os.unlink(tmp_path) + def get_font(size, bold=False): """Get a font, falling back to default if not available.""" font_names = [ - '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf' if bold else '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', - '/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf' if bold else '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf', - '/usr/share/fonts/TTF/DejaVuSans-Bold.ttf' if bold else '/usr/share/fonts/TTF/DejaVuSans.ttf', + "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf" + if bold + else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", + "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf" + if bold + else "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf", + "/usr/share/fonts/TTF/DejaVuSans-Bold.ttf" + if bold + else "/usr/share/fonts/TTF/DejaVuSans.ttf", ] for font_name in font_names: if os.path.exists(font_name): @@ -88,6 +102,7 @@ def get_font(size, bold=False): # Fallback to default return ImageFont.load_default() + def create_splash(output_path, logo_path, width, height, version, freecad_version, scale=1): """Create a splash screen image.""" # Scale dimensions @@ -97,11 +112,11 @@ def create_splash(output_path, logo_path, width, height, version, freecad_versio padding = int(30 * scale) # Create image with transparent background - img = Image.new('RGBA', (w, h), (0, 0, 0, 0)) + img = Image.new("RGBA", (w, h), (0, 0, 0, 0)) draw = ImageDraw.Draw(img) # Draw rounded rectangle background - bg_color = hex_to_rgb(COLORS['base']) + bg_color = hex_to_rgb(COLORS["mantle"]) create_rounded_rectangle(draw, (padding, padding, w - padding, h - padding), radius, bg_color) # Load and place logo @@ -125,7 +140,7 @@ def create_splash(output_path, logo_path, width, height, version, freecad_versio title_width = title_bbox[2] - title_bbox[0] title_x = (w - title_width) // 2 title_y = int(250 * scale) - draw.text((title_x, title_y), title, fill=hex_to_rgb(COLORS['text']), font=title_font) + draw.text((title_x, title_y), title, fill=hex_to_rgb(COLORS["text"]), font=title_font) # Draw version string version_font = get_font(int(12 * scale)) @@ -134,12 +149,15 @@ def create_splash(output_path, logo_path, width, height, version, freecad_versio version_width = version_bbox[2] - version_bbox[0] version_x = (w - version_width) // 2 version_y = title_y + int(35 * scale) - draw.text((version_x, version_y), version_str, fill=hex_to_rgb(COLORS['subtext0']), font=version_font) + draw.text( + (version_x, version_y), version_str, fill=hex_to_rgb(COLORS["subtext0"]), font=version_font + ) # Save - img.save(output_path, 'PNG') + img.save(output_path, "PNG") print(f"Created: {output_path}") + def create_about(output_path, logo_path, width, height, scale=1): """Create an about dialog image.""" # Scale dimensions @@ -147,7 +165,7 @@ def create_about(output_path, logo_path, width, height, scale=1): h = int(height * scale) # Create image - img = Image.new('RGBA', (w, h), hex_to_rgb(COLORS['base']) + (255,)) + img = Image.new("RGBA", (w, h), hex_to_rgb(COLORS["base"]) + (255,)) draw = ImageDraw.Draw(img) # Load and place logo @@ -163,18 +181,19 @@ def create_about(output_path, logo_path, width, height, scale=1): print(f"Warning: Could not load logo: {e}") # Save - img.save(output_path, 'PNG') + img.save(output_path, "PNG") print(f"Created: {output_path}") + def main(): - parser = argparse.ArgumentParser(description='Generate Kindred Create splash screens') - parser.add_argument('--version', default='0.1.0', help='Kindred Create version') - parser.add_argument('--freecad-version', default='1.0.0', help='FreeCAD version') + parser = argparse.ArgumentParser(description="Generate Kindred Create splash screens") + parser.add_argument("--version", default="0.1.0", help="Kindred Create version") + parser.add_argument("--freecad-version", default="1.0.0", help="FreeCAD version") args = parser.parse_args() script_dir = Path(__file__).parent - logo_path = script_dir / 'kindred-logo.svg' - icons_dir = script_dir.parent.parent / 'src' / 'Gui' / 'Icons' + logo_path = script_dir / "kindred-logo.svg" + icons_dir = script_dir.parent.parent / "src" / "Gui" / "Icons" if not logo_path.exists(): print(f"Error: Logo not found at {logo_path}") @@ -182,33 +201,31 @@ def main(): # Create splash screens (600x400 as per spec) create_splash( - icons_dir / 'kindredcreatesplash.png', + icons_dir / "kindredcreatesplash.png", logo_path, - 600, 400, + 600, + 400, args.version, args.freecad_version, - scale=1 + scale=1, ) # Create 2x version for HiDPI create_splash( - icons_dir / 'kindredcreatesplash_2x.png', + icons_dir / "kindredcreatesplash_2x.png", logo_path, - 600, 400, + 600, + 400, args.version, args.freecad_version, - scale=2 + scale=2, ) # Create about image - create_about( - icons_dir / 'kindredcreateabout.png', - logo_path, - 400, 200, - scale=1 - ) + create_about(icons_dir / "kindredcreateabout.png", logo_path, 400, 200, scale=1) print("\nSplash screen generation complete!") -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/src/Gui/SplashScreen.cpp b/src/Gui/SplashScreen.cpp index 656cb64fb2..66ed55dd2a 100644 --- a/src/Gui/SplashScreen.cpp +++ b/src/Gui/SplashScreen.cpp @@ -360,9 +360,6 @@ QPixmap SplashScreen::splashImage() fontExe.setPointSizeF(20.0); QFontMetrics metricExe(fontExe); int l = QtTools::horizontalAdvance(metricExe, title); - if (title == QLatin1String("Kindred Create")) { - // For Kindred Create splash, we draw the title as part of the dynamic rendering - } int w = splash_image.width(); int h = splash_image.height(); @@ -386,13 +383,16 @@ QPixmap SplashScreen::splashImage() QColor color(QString::fromStdString(tc->second)); if (color.isValid()) { painter.setPen(color); - painter.setFont(fontExe); - if (title != QLatin1String("FreeCAD")) { - // FreeCAD's Splashscreen already contains the EXE name, no need to draw it - painter.drawText(x, y, title); + if (title != QLatin1String("Kindred Create")) { + // Kindred Create's splash PNG already contains the title and version + painter.setFont(fontExe); + if (title != QLatin1String("FreeCAD")) { + // FreeCAD's Splashscreen already contains the EXE name, no need to draw it + painter.drawText(x, y, title); + } + painter.setFont(fontVer); + painter.drawText(x + (l + 235), y - 7, version); } - painter.setFont(fontVer); - painter.drawText(x + (l + 235), y - 7, version); QColor warningColor(QString::fromStdString(wc->second)); if (suffix == QLatin1String("dev") && warningColor.isValid()) { fontVer.setPointSizeF(14.0);