Visitar URL original
Scale images correctly (#163) · flutter/packages@1152505 · GitHub
Skip to content

Commit 1152505

Browse files
authored
Scale images correctly (#163)
1 parent ba536d2 commit 1152505

2 files changed

Lines changed: 96 additions & 11 deletions

File tree

‎packages/vector_graphics/lib/src/listener.dart‎

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,29 @@ class _PatternState {
108108
ui.PictureRecorder? recorder;
109109
}
110110

111+
/// Used by [FlutterVectorGraphicsListener] for testing purposes.
112+
@visibleForTesting
113+
abstract class PictureFactory {
114+
/// Allows const subclasses.
115+
const PictureFactory();
116+
117+
/// Create a picture recorder.
118+
ui.PictureRecorder createPictureRecorder();
119+
120+
/// Create a canvas from the recorder.
121+
ui.Canvas createCanvas(ui.PictureRecorder recorder);
122+
}
123+
124+
class _DefaultPictureFactory implements PictureFactory {
125+
const _DefaultPictureFactory();
126+
127+
@override
128+
ui.Canvas createCanvas(ui.PictureRecorder recorder) => ui.Canvas(recorder);
129+
130+
@override
131+
ui.PictureRecorder createPictureRecorder() => ui.PictureRecorder();
132+
}
133+
111134
/// A listener implementation for the vector graphics codec that converts the
112135
/// format into a [ui.Picture].
113136
class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
@@ -119,26 +142,31 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
119142
Locale? locale,
120143
TextDirection? textDirection,
121144
bool clipViewbox = true,
145+
@visibleForTesting
146+
PictureFactory pictureFactory = const _DefaultPictureFactory(),
122147
}) {
123-
final ui.PictureRecorder recorder = ui.PictureRecorder();
124-
final ui.Canvas canvas = ui.Canvas(recorder);
148+
final ui.PictureRecorder recorder = pictureFactory.createPictureRecorder();
125149
return FlutterVectorGraphicsListener._(
126-
canvas,
150+
pictureFactory,
127151
recorder,
152+
pictureFactory.createCanvas(recorder),
128153
locale,
129154
textDirection,
130155
clipViewbox,
131156
);
132157
}
133158

134159
FlutterVectorGraphicsListener._(
135-
this._canvas,
160+
this._pictureFactory,
136161
this._recorder,
162+
this._canvas,
137163
this._locale,
138164
this._textDirection,
139165
this._clipViewbox,
140166
);
141167

168+
final PictureFactory _pictureFactory;
169+
142170
final Locale? _locale;
143171
final TextDirection? _textDirection;
144172
final bool _clipViewbox;
@@ -349,8 +377,9 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
349377
double height, Float64List transform) {
350378
assert(_currentPattern == null);
351379
_currentPattern = _PatternConfig(patternId, width, height, transform);
352-
_patterns[patternId]!.recorder = ui.PictureRecorder();
353-
final ui.Canvas newCanvas = ui.Canvas(_patterns[patternId]!.recorder!);
380+
_patterns[patternId]!.recorder = _pictureFactory.createPictureRecorder();
381+
final ui.Canvas newCanvas =
382+
_pictureFactory.createCanvas(_patterns[patternId]!.recorder!);
354383
newCanvas.clipRect(ui.Offset(x, y) & ui.Size(width, height));
355384
_patterns[patternId]!.canvas = newCanvas;
356385
}
@@ -360,7 +389,13 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
360389
ui.PictureRecorder? patternRecorder, ui.Canvas canvas) {
361390
final FlutterVectorGraphicsListener patternListener =
362391
FlutterVectorGraphicsListener._(
363-
canvas, patternRecorder!, _locale, _textDirection, _clipViewbox);
392+
_pictureFactory,
393+
patternRecorder!,
394+
canvas,
395+
_locale,
396+
_textDirection,
397+
_clipViewbox,
398+
);
364399

365400
patternListener._size =
366401
ui.Size(currentPattern!._width, currentPattern._height);
@@ -561,10 +596,11 @@ class FlutterVectorGraphicsListener extends VectorGraphicsCodecListener {
561596
_canvas.save();
562597
_canvas.transform(transform);
563598
}
564-
paintImage(
565-
canvas: _canvas,
566-
rect: ui.Rect.fromLTWH(x, y, width, height),
567-
image: image,
599+
_canvas.drawImageRect(
600+
image,
601+
ui.Rect.fromLTRB(0, 0, image.width.toDouble(), image.height.toDouble()),
602+
ui.Rect.fromLTWH(x, y, width, height),
603+
Paint(),
568604
);
569605
if (transform != null) {
570606
_canvas.restore();

‎packages/vector_graphics/test/listener_test.dart‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:convert' show base64;
56
import 'dart:typed_data';
67
import 'dart:ui' as ui;
78

@@ -18,6 +19,9 @@ void main() {
1819
</svg>
1920
''';
2021

22+
const String bluePngPixel =
23+
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==';
24+
2125
late ByteData vectorGraphicBuffer;
2226

2327
setUpAll(() async {
@@ -60,4 +64,49 @@ void main() {
6064
expect(imageBytes.first, 0xFF000000);
6165
expect(imageBytes.last, 0xFF000000);
6266
}, skip: kIsWeb);
67+
68+
test('Scales image correctly', () async {
69+
final TestPictureFactory factory = TestPictureFactory();
70+
final FlutterVectorGraphicsListener listener =
71+
FlutterVectorGraphicsListener(
72+
pictureFactory: factory,
73+
);
74+
listener.onImage(0, 0, base64.decode(bluePngPixel));
75+
await listener.waitForImageDecode();
76+
listener.onDrawImage(0, 10, 10, 30, 30, null);
77+
final Invocation drawRect = factory.fakeCanvases.first.invocations.single;
78+
expect(drawRect.isMethod, true);
79+
expect(drawRect.memberName, #drawImageRect);
80+
expect(
81+
drawRect.positionalArguments[1],
82+
const ui.Rect.fromLTRB(0, 0, 1, 1),
83+
);
84+
expect(
85+
drawRect.positionalArguments[2],
86+
const ui.Rect.fromLTRB(10, 10, 40, 40),
87+
);
88+
});
89+
}
90+
91+
class TestPictureFactory implements PictureFactory {
92+
final List<FakeCanvas> fakeCanvases = <FakeCanvas>[];
93+
@override
94+
ui.Canvas createCanvas(ui.PictureRecorder recorder) {
95+
fakeCanvases.add(FakeCanvas());
96+
return fakeCanvases.last;
97+
}
98+
99+
@override
100+
ui.PictureRecorder createPictureRecorder() => FakePictureRecorder();
101+
}
102+
103+
class FakePictureRecorder extends Fake implements ui.PictureRecorder {}
104+
105+
class FakeCanvas implements ui.Canvas {
106+
final List<Invocation> invocations = <Invocation>[];
107+
108+
@override
109+
dynamic noSuchMethod(Invocation invocation) {
110+
invocations.add(invocation);
111+
}
63112
}

0 commit comments

Comments
 (0)