Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVG image is not displayed when styles and classes are used - drawing issue still in ^2.0.10+1 #1082

Open
s681562 opened this issue Jun 24, 2024 · 6 comments

Comments

@s681562
Copy link

s681562 commented Jun 24, 2024

If you find in your svg style...style and class..."..." than nothing is show up.

flutter_svg can not handle a path with class attribute.
A path with class attribute are not drawing on your screen in your flutter app.

For instance Adobe Illustrator 26.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) will summarize all color settings in a style set.
And all pathes or rect or circles etc. will rewrite with an class attribute, referencing a style set in the first lines of your svg.

Please fix it asap.

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 2294.1 283.5" style="enable-background:new 0 0 2294.1 283.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:#E40422;}
</style>
<rect y="0.1" class="st0" width="2294.1" height="283.5"/>
<path class="st1" d="M1875.4,188.8h13.2c0.9,0,1.6-0.7,1.6-1.6v-62.3c0-0.8,0.5-1.1,0.9-0.3l35.6,63.1c0.4,0.7,1.2,1.1,2,1.1h15.2
c0.9,0,1.6-0.7,1.6-1.6V96c0-0.9-0.7-1.6-1.6-1.6h-13.2c-0.9,0-1.6,0.7-1.6,1.6v62.4c0,0.8-0.5,1.1-0.9,0.3l-35.6-63.2
c-0.4-0.7-1.2-1.1-2-1.1h-15.2c-0.9,0-1.6,0.7-1.6,1.6v91.2C1873.8,188.1,1874.4,188.8,1875.4,188.8z"/>
<path class="st1" d="M1600.6,188.8h49.1c0.9,0,1.6-0.7,1.6-1.6v-12.4c0-0.9-0.7-1.6-1.6-1.6h-33.5c-0.5,0-0.8-0.4-0.8-0.8v-22.7
c0-0.5,0.4-0.8,0.8-0.8h33.5c0.9,0,1.6-0.7,1.6-1.6V135c0-0.9-0.7-1.6-1.6-1.6h-33.5c-0.5,0-0.8-0.3-0.8-0.8v-21.7
c0-0.5,0.4-0.8,0.8-0.8h33.5c0.9,0,1.6-0.7,1.6-1.6V96c0-0.9-0.7-1.6-1.6-1.6h-49.1c-0.9,0-1.6,0.7-1.6,1.6v91.2
C1599,188.1,1599.7,188.8,1600.6,188.8z"/>

... please not this issue.

The flutter_svg can not handle style and class attribute in version ^2.0.10+1.

@ydotmalik
Copy link

All styles have to be inlined with the node.

@s681562
Copy link
Author

s681562 commented Jul 23, 2024

@ydotmalik: So this means frankly speaking... reusing styles are not supported in ^2.0.10+1.
If you using Adobe Illustrator you will have a lot of additional work to adjust outcoming svg for ^2.0.10+1.
Only browser like firefox, chrome etc. can draw it without headache directly.

In flutter/dart still with ^2.0.10+1 we have to use it like:

<path stroke="#000" name="12" id="svg_10" d="m678.99999,440.99997l29,0l0,20l-29,0l0,-20z" opacity="0.1" stroke-linecap="undefined" stroke-linejoin="undefined" fill="#00ff00"/>

<path stroke="#000" name="12" id="svg_11" d="m816.99999,456.99997l26,0l0,18l-26,0l0,-18z" opacity="0.1" stroke-linecap="undefined" stroke-linejoin="undefined" fill="#00ff00"/>

<path stroke="#000" name="12" id="svg_12" d="m881.99999,455.99997l27,0l0,20l-27,0l0,-20z" opacity="0.1" stroke-linecap="undefined" stroke-linejoin="undefined" fill="#00ff00"/>

So this is not an issue - it is an "can not support style reusing" feature.

Understand.

@ydotmalik
Copy link

Yes, you have to inline as you mentioned. This is how flutter_svg has behaved since the beginning.

@subzero911
Copy link

subzero911 commented Jul 24, 2024

Same here:

SVG icon:

<svg width="52" height="52" viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="52" height="52" fill="#F2F3F7" style="fill:#F2F3F7;fill:color(display-p3 0.9490 0.9529 0.9686);fill-opacity:1;"/>
<path d="M40 40H12V12H40V26.593L39.9999 25.2424H38.1326L38.1217 19.2825L35.4834 25.2424H33.8844L31.2321 19.2693V25.2424H27.5265L26.8292 23.5438H23.0352L22.3313 25.2424H20.3511L23.6087 17.6226H26.3189L29.4157 24.8416V17.6226H32.3931L34.7741 22.7962L36.966 17.6226H39.9999V16.1128H35.8745L34.6829 18.8619L33.4706 16.1128H27.9016V17.3717L27.2835 16.113H22.5343L18 26.7436H24.2388V35.8825H33.8779L35.4291 34.2294L36.89 35.8827L40 35.8871L40 40ZM24.9252 18.9251L23.6847 21.9557H26.1734L24.9252 18.9251Z" fill="#0971CE" style="fill:#0971CE;fill:color(display-p3 0.0353 0.4431 0.8078);fill-opacity:1;"/>
<path d="M40 32.3426V28.8225L38.4346 30.5896L40 32.3426Z" fill="#0971CE" style="fill:#0971CE;fill:color(display-p3 0.0353 0.4431 0.8078);fill-opacity:1;"/>
<path d="M40 26.7618H37.772L35.4563 29.2589L33.2153 26.7618H25.8898V34.3869H33.1034L35.4344 31.8645L37.6785 34.3869H40L36.609 30.5896L40 26.7618ZM32.1791 32.7935H27.7005V31.2783H31.6993V29.7216H27.7005V28.3422H32.267L34.256 30.559L32.1791 32.7935Z" fill="#0971CE" style="fill:#0971CE;fill:color(display-p3 0.0353 0.4431 0.8078);fill-opacity:1;"/>
</svg>

not rendered.

The same SVG without style tags:

<svg width="52" height="52" viewBox="0 0 52 52" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="52" height="52" fill="#F2F3F7"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 40H40V12H12V40Z" fill="#0971CE"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.1326 25.2424H39.9999V25.2453H40V26.7618H37.772L35.4563 29.2589L33.2153 26.7618H25.8898V34.3869H33.1034L35.4344 31.8645L37.6785 34.3869H40V35.8871L36.89 35.8827L35.4291 34.2294L33.8779 35.8825H24.2388V26.7436H23.4426H18L22.5343 16.113H27.2835L27.9016 17.3717V16.1128H33.4706L34.6829 18.8619L35.8745 16.1128H39.9999V17.6226H36.966L34.7741 22.7962L32.3931 17.6226H29.4157V24.8416L26.3189 17.6226H23.6087L20.3511 25.2424H22.3313L23.0352 23.5438H26.8292L27.5265 25.2424H31.2321V19.2693L33.8844 25.2424H35.4834L38.1217 19.2825L38.1326 25.2424ZM40 34.3869V32.3426L38.4346 30.5896L40 28.8225V26.7618L36.609 30.5896L40 34.3869ZM24.9252 18.9251L26.1734 21.9557H23.6847L24.9252 18.9251ZM27.7005 32.7935H32.1791L34.256 30.559L32.267 28.3422H27.7005V29.7216H31.6993V31.2783H27.7005V32.7935Z" fill="white"/>
</svg>

rendered correctly.

@JoSeTe4ever
Copy link

I am also having the same issue.

The point is that my svg comes from an API. And the style tags are there.

I am thrilled that this feature is not supported in the package 👀. Is there any alternative to render this style classes in a flutter app ?

thank you !

JoSeTe4ever added a commit to JoSeTe4ever/first_flutter_app that referenced this issue Sep 13, 2024
@studionexus-lk
Copy link

try converting to compatible SVG before importing, instead of file ,
use flutter_svg: ^1.1.6 cz new vesion missing parse,DrawableRoot etc

  Future<void> pickAndImportSvg({bool locked = false}) async {  // Added locked parameter
    try {
      FilePickerResult? result = await FilePicker.platform.pickFiles(
        type: FileType.custom,
        allowedExtensions: ['svg'],
      );
      if (result != null) {
        final file = File(result.files.single.path!);
        final svgString = await file.readAsString();
        await importSvgFromString(svgString, result.files.single.name, locked: locked);
      }
    } catch (e) {
      showError('Error importing SVG file: $e');
    }
  }


 Future<void> importSvgFromString(String svgString, String name, {bool locked = false}) async {
    try {
      // First check if there's any CSS to convert
      final document = xml.XmlDocument.parse(svgString);
      final hasStyle = document.findAllElements('style').isNotEmpty;

      // Convert CSS to inline attributes if needed
      String processedSvgString = svgString;
      if (hasStyle) {
        final converter = SvgCssConverter();
        processedSvgString = converter.convertCssToInline(svgString);
      }

      // Parse the processed SVG string
      final DrawableRoot svgRoot = await svg.fromSvgString(processedSvgString, name)
          .then((result) => result as DrawableRoot);

      
      });
    } catch (e) {
      print('SVG Import Error: $e'); // For debugging
      showError('Error parsing SVG: ${e.toString()}');
    }
  }
// svg_css_converter.dart

import 'package:collection/collection.dart';
import 'package:xml/xml.dart' as xml;

class CssRule {
  final String selector;
  final Map<String, String> declarations;

  CssRule(this.selector, this.declarations);
}

class SvgCssConverter {
  List<CssRule> _parseCssRules(String cssContent) {
    final rules = <CssRule>[];
    cssContent = cssContent.replaceAll(RegExp(r'/\*[\s\S]*?\*/'), '');

    final rulePattern = RegExp(r'([^{]+)\s*{\s*([^}]+)\s*}');
    final matches = rulePattern.allMatches(cssContent);

    for (final match in matches) {
      if (match.groupCount >= 2) {
        final selector = match.group(1)?.trim() ?? '';
        final declarationsStr = match.group(2)?.trim() ?? '';

        final declarations = <String, String>{};
        final declarationsList = declarationsStr.split(';');

        for (var declaration in declarationsList) {
          declaration = declaration.trim();
          if (declaration.isEmpty) continue;

          final parts = declaration.split(':').map((e) => e.trim()).toList();
          if (parts.length == 2) {
            declarations[parts[0]] = parts[1];
          }
        }

        rules.add(CssRule(selector, declarations));
      }
    }

    return rules;
  }

  void _applyRulesToElement(xml.XmlElement element, CssRule rule) {
    bool shouldApply = false;

    if (rule.selector.startsWith('.')) {
      // Class selector
      final className = rule.selector.substring(1);
      final classAttr = element.getAttribute('class');
      if (classAttr != null) {
        final classes = classAttr.split(' ');
        shouldApply = classes.contains(className);
        if (shouldApply) {
          // Remove the processed class
          element.setAttribute('class',
              classes.where((c) => c != className).join(' ').trim());
        }
      }
    } else if (rule.selector.startsWith('#')) {
      // ID selector
      final id = rule.selector.substring(1);
      shouldApply = element.getAttribute('id') == id;
    } else {
      // Element selector
      shouldApply = element.name.local == rule.selector;
    }

    if (shouldApply) {
      _applyDeclarationsToElement(element, rule.declarations);
    }

    // Recursively process child elements
    for (var child in element.childElements) {
      _applyRulesToElement(child, rule);
    }
  }

  void _applyDeclarationsToElement(xml.XmlElement element, Map<String, String> declarations) {
    for (final entry in declarations.entries) {
      final property = entry.key;
      var value = entry.value;

      switch (property) {
        case 'fill':
        case 'stroke':
        case 'opacity':
        case 'stroke-width':
        case 'stroke-opacity':
        case 'fill-opacity':
          element.setAttribute(property, value);
          break;

        case 'transform':
          element.setAttribute('transform', value);
          break;

        case 'background-color':
          element.setAttribute('fill', value);
          break;

        case 'color':
          if (!declarations.containsKey('fill')) {
            element.setAttribute('fill', value);
          }
          break;
      }
    }
  }

  String convertCssToInline(String svgContent) {
    try {
      // Parse the SVG content
      final document = xml.XmlDocument.parse(svgContent);

      // Find all style elements
      final styleElements = document.findAllElements('style').toList();

      for (final styleElement in styleElements) {
        final cssContent = styleElement.text;
        final rules = _parseCssRules(cssContent);

        // Apply rules to the SVG elements
        final svgElement = document.findElements('svg').first;
        for (final rule in rules) {
          _applyRulesToElement(svgElement, rule);
        }

        // Remove the processed style element
        styleElement.remove();
      }

      // Convert back to string with proper XML formatting
      return document.toXmlString(pretty: true);
    } catch (e) {
      print('Error processing SVG: $e');
      return svgContent; // Return original content if processing fails
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants