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

allow specifying target size when parsing svg #240

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion packages/vector_graphics/lib/src/listener.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';

Expand Down Expand Up @@ -62,6 +63,7 @@ Future<PictureInfo> decodeVectorGraphics(
required bool clipViewbox,
required BytesLoader loader,
VectorGraphicsErrorListener? onError,
Size? targetSize,
}) {
try {
// We might be in a test that's using a fake async zone. Make sure that any
Expand All @@ -86,6 +88,7 @@ Future<PictureInfo> decodeVectorGraphics(
textDirection: textDirection,
clipViewbox: clipViewbox,
onError: onError,
targetSize: targetSize,
);
DecodeResponse response = _codec.decode(data, listener);
if (response.complete) {
Expand Down Expand Up @@ -207,6 +210,7 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
@visibleForTesting
PictureFactory pictureFactory = const _DefaultPictureFactory(),
VectorGraphicsErrorListener? onError,
Size? targetSize,
}) {
final PictureRecorder recorder = pictureFactory.createPictureRecorder();
return FlutterVectorGraphicsListener._(
Expand All @@ -217,6 +221,7 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
locale,
textDirection,
clipViewbox,
targetSize,
onError: onError,
);
}
Expand All @@ -228,7 +233,8 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
this._canvas,
this._locale,
this._textDirection,
this._clipViewbox, {
this._clipViewbox,
this._targetSize, {
this.onError,
});

Expand All @@ -239,6 +245,7 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
final Locale? _locale;
final TextDirection? _textDirection;
final bool _clipViewbox;
final Size? _targetSize;

final PictureRecorder _recorder;
final Canvas _canvas;
Expand Down Expand Up @@ -474,6 +481,7 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
_locale,
_textDirection,
_clipViewbox,
null,
);

patternListener._size =
Expand Down Expand Up @@ -558,6 +566,14 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {

@override
void onSize(double width, double height) {
final double targetWidth = _targetSize?.width ?? width;
final double targetHeight = _targetSize?.height ?? height;

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

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

if (_clipViewbox) {
_canvas.clipRect(Offset.zero & Size(width, height));
}
Expand Down
5 changes: 3 additions & 2 deletions packages/vector_graphics/lib/src/vector_graphics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import 'package:vector_graphics_codec/vector_graphics_codec.dart';

import 'html_render_vector_graphics.dart';
import 'loader.dart';
import 'listener.dart';
import 'loader.dart';
import 'render_object_selection.dart';
import 'render_vector_graphic.dart';

Expand Down Expand Up @@ -680,6 +679,7 @@ class VectorGraphicUtilities {
BuildContext? context, {
bool clipViewbox = true,
VectorGraphicsErrorListener? onError,
Size? targetSize,
}) async {
TextDirection textDirection = TextDirection.ltr;
Locale locale = ui.PlatformDispatcher.instance.locale;
Expand All @@ -696,6 +696,7 @@ class VectorGraphicUtilities {
loader: loader,
clipViewbox: clipViewbox,
onError: onError,
targetSize: targetSize,
);
} catch (e) {
debugPrint('Failed to decode $loader');
Expand Down
88 changes: 88 additions & 0 deletions packages/vector_graphics/test/scale/scale_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'dart:ui' as ui;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:vector_graphics/src/listener.dart';
import 'package:vector_graphics_compiler/vector_graphics_compiler.dart';

import '../caching_test.dart';

void main() {
TestWidgetsFlutterBinding.ensureInitialized();

late final ByteData vectorGraphicBuffer;
const String svgString = '''
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 21H7V8L14 1L15.25 2.25C15.3667 2.36667 15.4625 2.525 15.5375 2.725C15.6125 2.925 15.65 3.11667 15.65 3.3V3.65L14.55 8H21C21.5333 8 22 8.2 22.4 8.6C22.8 9 23 9.46667 23 10V12C23 12.1167 22.9833 12.2417 22.95 12.375C22.9167 12.5083 22.8833 12.6333 22.85 12.75L19.85 19.8C19.7 20.1333 19.45 20.4167 19.1 20.65C18.75 20.8833 18.3833 21 18 21ZM9 19H18L21 12V10H12L13.35 4.5L9 8.85V19ZM7 8V10H4V19H7V21H2V8H7Z" fill="#0066FF"/>
</svg>
''';

setUpAll(() async {
final Uint8List bytes = encodeSvg(
xml: svgString,
debugName: 'test',
enableClippingOptimizer: false,
enableMaskingOptimizer: false,
enableOverdrawOptimizer: false,
);
vectorGraphicBuffer = bytes.buffer.asByteData();
});

setUp(() {
imageCache.clear();
imageCache.clearLiveImages();
});

Future<ui.Image> _decode({
required Size target,
}) async {
final PictureInfo info = await decodeVectorGraphics(
vectorGraphicBuffer,
locale: ui.PlatformDispatcher.instance.locale,
textDirection: ui.TextDirection.ltr,
clipViewbox: true,
loader: TestBytesLoader(vectorGraphicBuffer),
targetSize: target,
);
return info.picture.toImageSync(
target.width.toInt(),
target.height.toInt(),
);
}

testWidgets('resizes to the same size', (_) async {
final ui.Image image = await _decode(
target: const Size(24, 24),
);

await expectLater(
image,
matchesGoldenFile('thumb_up_24px.png'),
);
});

testWidgets('resizes to larger size', (_) async {
final ui.Image image = await _decode(
target: const Size(64, 64),
);

await expectLater(
image,
matchesGoldenFile('thumb_up_64px.png'),
);
});

testWidgets('resizes to smaller size', (_) async {
final ui.Image image = await _decode(
target: const Size(16, 16),
);

await expectLater(
image,
matchesGoldenFile('thumb_up_16px.png'),
);
});
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.