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

[v2.0.5] Svg not properly resized when passed to vg.loadPicture() #971

Open
dugernierg opened this issue Aug 2, 2023 · 6 comments · May be fixed by dnfield/vector_graphics#240
Open

[v2.0.5] Svg not properly resized when passed to vg.loadPicture() #971

dugernierg opened this issue Aug 2, 2023 · 6 comments · May be fixed by dnfield/vector_graphics#240

Comments

@dugernierg
Copy link

dugernierg commented Aug 2, 2023

I am using flutter_svg to handle SVG files that needs to be resized before getting formatted as PNGs to be used as markers on GoogleMap (why GoogleMap doesn't handle SVG is beyond me, but not the topic of this post). Because I haven't find a way to convert an SvgPicture directly into ByteData with the ImageByteFormat.png format, I'm doing a bit of a workaround by converting it into an Image first.

   final width = 100.0;
   final height = 140.0;
   final svgPicture = SvgPicture.asset(
      assetPath,
      height: height,
      width: width,
   );

    final pictureInfo = await vg.loadPicture(svgPicture.bytesLoader, null);
    final image = await pictureInfo.picture.toImage(width.round(), height.round());
    final bytes = await image.toByteData(format: ImageByteFormat.png);
    final marker = BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());

I follow what was recommended here. However, no matter what value I give to width and height, the file will be shown in its original size. As far as I can tell, the bytesLoader ignores the values passed to SvgPicture.asset() and uses the one inside the file instead (see picture below).

image

I'm not sure if it's intended or not, but it's at the very least counterintuitive in my opinion.

@HasanShaddadKangaroo
Copy link

@dugernierg

Did you find any workaround for this or maybe another way to implement it?

@dugernierg
Copy link
Author

dugernierg commented Sep 1, 2023

@HasanShaddadKangaroo I ended up parsing the svg string myself by doing the following steps:

  • matched on 'height="(.*?)"', 'width="(.*?)"' and 'viewBox="(.*?)"' RegExps to find the existing values as strings.
  • did some replaceAll() on those strings to isolate the values then parse them as double.
  • did a replaceFirst on the same RegExps from step one to switch the old values by values*ratio: replaceFirst(RegExp('height="(.*?)"'), 'height="$newHeight"')
  • applied a transform=scale on all paths with: replaceAll('<path', '<path transform="scale($devicePixelRatio)" ')

Applying the scale without modifying all height, width and viewBox doesn't work.

It's a 25 lines workaround that's blind enough to the SVG syntax for us to use, but it's also because we know how our SVGs are written.

@eEQK
Copy link

eEQK commented Sep 18, 2023

I've forked the repo and made a hacky fix for that, I most likely won't create a PR unless Dan himself says otherwise - the reason being it most likely isn't a proper solution (but more of a workaround)

Import using:

  flutter_svg:
    git:
      url: https://github.com/XperiTech/flutter_svg
      path: packages/flutter_svg
      ref: e969f6c510949eee75b3e93269411e8815fd1f45

(flutter_svg also contains a ref for vector_graphics so it shouldn't be possible for me or anyone else to inject malicious code - you can also simply fork the repo)

The way you can use it is by specifying targetSize:

await vg.loadPicture(
      SvgStringLoader(svgString),
      context,
      targetSize: Size(80, 80),
    );

the code inside will calculate how much it should scale each axis (width and height are taken from the svg file itself, while target is what you specify):

    final double sx = targetWidth / width;
    final double sy = targetHeight / height;

and then it will choose the smallest one to scale the svg:

      _canvas.scale(min(sx, sy));

@dnfield
Copy link
Owner

dnfield commented Sep 18, 2023

I've forked the repo and made a hacky fix for that, I most likely won't create a PR unless Dan himself says otherwise - the reason being it most likely isn't a proper solution (but more of a workaround)

Import using:

I think if you add some tests for this it would be a reasonable way to handle this upstream.

@osnipezzini
Copy link

Some news about this ?

@sirkalmi
Copy link

sirkalmi commented Aug 7, 2024

I solved it this way in my agony, I'm waiting for the error correction so that I can delete the seemingly unnecessary subsequent resizing.

static Future<ui.Image> imageFromSvgAsset(String fileName, {String? svgString, Size? size, Map<String, String>? replace, String? subDirectory}) async {
  svgString ??= await readSvgString(fileName, replace: replace, subDirectory: subDirectory);
  final pictureInfo = await vg.loadPicture(SvgStringLoader(svgString), null);

  //https://github.com/dnfield/flutter_svg/issues/971
  final image = await pictureInfo.picture.toImage(pictureInfo.size.width.round(), pictureInfo.size.height.round());

  final devicePixelRatio = Get.mediaQuery.devicePixelRatio;
  final targetWidth = (size?.width ?? image.width) * devicePixelRatio;
  final targetHeight = (size?.height ?? image.height) * devicePixelRatio;
  return await resizeImage(image, targetWidth.toInt(), targetHeight.toInt());
}
static Future<ui.Image> resizeImage(ui.Image image, int targetWidth, int targetHeight) async {
  final recorder = ui.PictureRecorder();
  final canvas = Canvas(recorder);

  canvas.drawImageRect(
    image,
    Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()),
    Rect.fromLTWH(0, 0, targetWidth.toDouble(), targetHeight.toDouble()),
    Paint(),
  );

  final picture = recorder.endRecording();
  final newImage = await picture.toImage(targetWidth, targetHeight);

  return newImage;
}

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

Successfully merging a pull request may close this issue.

6 participants