my-multiplayer-app-2 / tools /svg-group-analysis.py
Jaimodiji's picture
Upload folder using huggingface_hub
d9eba27 verified
Raw
History Blame
6.17 kB
#!/usr/bin/env python3
"""
Deep SVG Group Analysis - Find what's being missed
"""
import re
import sys
def analyze_groups(svg_content):
"""Analyze group structure and transforms"""
# Find all groups
group_pattern = r'<(?:\w+:)?g\s+([^>]*)>'
groups = []
for match in re.finditer(group_pattern, svg_content, re.IGNORECASE):
attrs = match.group(1)
pos = match.start()
# Extract transform
transform_match = re.search(r'transform="([^"]*)"', attrs)
transform = transform_match.group(1) if transform_match else None
groups.append({
'position': pos,
'attrs': attrs,
'transform': transform
})
return groups
def find_elements_in_groups(svg_content):
"""Find which elements are inside groups vs top-level"""
# Count total elements
all_paths = len(re.findall(r'<(?:\w+:)?path\s+', svg_content, re.IGNORECASE))
all_images = len(re.findall(r'<(?:\w+:)?image\s+', svg_content, re.IGNORECASE))
# Remove group content and count remaining
no_groups = re.sub(r'<(?:\w+:)?g[^>]*>[\s\S]*?</(?:\w+:)?g>', '', svg_content)
top_level_paths = len(re.findall(r'<(?:\w+:)?path\s+', no_groups, re.IGNORECASE))
top_level_images = len(re.findall(r'<(?:\w+:)?image\s+', no_groups, re.IGNORECASE))
return {
'total_paths': all_paths,
'paths_in_groups': all_paths - top_level_paths,
'top_level_paths': top_level_paths,
'total_images': all_images,
'images_in_groups': all_images - top_level_images,
'top_level_images': top_level_images
}
def find_bounding_boxes(svg_content):
"""Find coordinate ranges to detect if lower half is missing"""
# Extract all Y coordinates from paths
y_coords = []
# From path d attributes - look for M, L, V commands with Y values
path_pattern = r'd="([^"]*)"'
for match in re.finditer(path_pattern, svg_content):
d = match.group(1)
# Extract numbers after M, L commands (every second number is Y)
coords = re.findall(r'[ML]\s*([-\d.]+)\s+([-\d.]+)', d, re.IGNORECASE)
for x, y in coords:
try:
y_coords.append(float(y))
except:
pass
if y_coords:
return {
'min_y': min(y_coords),
'max_y': max(y_coords),
'y_range': max(y_coords) - min(y_coords)
}
return None
def analyze_nested_groups(svg_content):
"""Find deeply nested groups"""
# Find group opening/closing tags
opens = [(m.start(), 'open') for m in re.finditer(r'<(?:\w+:)?g\s+[^>]*>', svg_content, re.IGNORECASE)]
closes = [(m.start(), 'close') for m in re.finditer(r'</(?:\w+:)?g>', svg_content, re.IGNORECASE)]
all_tags = sorted(opens + closes, key=lambda x: x[0])
max_depth = 0
current_depth = 0
depth_counts = {}
for pos, tag_type in all_tags:
if tag_type == 'open':
current_depth += 1
max_depth = max(max_depth, current_depth)
depth_counts[current_depth] = depth_counts.get(current_depth, 0) + 1
else:
current_depth -= 1
return {
'max_nesting_depth': max_depth,
'groups_at_each_depth': depth_counts
}
def check_transform_types(svg_content):
"""Check what transform types are used"""
transforms = re.findall(r'transform="([^"]*)"', svg_content)
types = {
'matrix': 0,
'translate': 0,
'scale': 0,
'rotate': 0,
'skew': 0
}
for t in transforms:
if 'matrix' in t:
types['matrix'] += 1
if 'translate' in t:
types['translate'] += 1
if 'scale' in t:
types['scale'] += 1
if 'rotate' in t:
types['rotate'] += 1
if 'skew' in t:
types['skew'] += 1
return types
def main():
if len(sys.argv) < 2:
print("Usage: python svg-group-analysis.py <file.svg>")
sys.exit(1)
filepath = sys.argv[1]
with open(filepath, 'r') as f:
content = f.read()
print(f"\n{'='*60}")
print(f"SVG GROUP ANALYSIS: {filepath}")
print('='*60)
# Basic counts
elem_counts = find_elements_in_groups(content)
print(f"\n📊 ELEMENT DISTRIBUTION:")
print(f" Total paths: {elem_counts['total_paths']}")
print(f" - In groups: {elem_counts['paths_in_groups']}")
print(f" - Top level: {elem_counts['top_level_paths']}")
print(f" Total images: {elem_counts['total_images']}")
print(f" - In groups: {elem_counts['images_in_groups']}")
print(f" - Top level: {elem_counts['top_level_images']}")
# Group nesting
nesting = analyze_nested_groups(content)
print(f"\n📁 GROUP NESTING:")
print(f" Max depth: {nesting['max_nesting_depth']}")
print(f" Groups at each depth: {nesting['groups_at_each_depth']}")
# Transforms
transforms = check_transform_types(content)
print(f"\n🔄 TRANSFORMS USED:")
for t, count in transforms.items():
if count > 0:
print(f" {t}: {count}")
# Groups with transforms
groups = analyze_groups(content)
groups_with_transforms = [g for g in groups if g['transform']]
print(f"\n🔧 GROUPS WITH TRANSFORMS: {len(groups_with_transforms)}")
for g in groups_with_transforms[:5]:
print(f" transform: {g['transform'][:60]}...")
# Bounding box
bbox = find_bounding_boxes(content)
if bbox:
print(f"\n📐 Y-COORDINATE RANGE:")
print(f" Min Y: {bbox['min_y']:.2f}")
print(f" Max Y: {bbox['max_y']:.2f}")
print(f" Range: {bbox['y_range']:.2f}")
# ViewBox
viewbox_match = re.search(r'viewBox="([^"]*)"', content)
if viewbox_match:
vb = viewbox_match.group(1).split()
if len(vb) >= 4:
vb_height = float(vb[3])
print(f" ViewBox height: {vb_height}")
if bbox:
coverage = (bbox['max_y'] - bbox['min_y']) / vb_height * 100
print(f" Content covers: {coverage:.1f}% of viewBox height")
if __name__ == '__main__':
main()