David PHAM-VAN

Optimize memory footprint

... ... @@ -12,6 +12,7 @@
- Fix context painting empty Table
- Fix Text decoration placements
- Improve image buffer management
- Optimize memory footprint
## 1.5.0
... ...
... ... @@ -18,9 +18,9 @@
part of pdf;
class Ascii85Encoder extends Converter<List<int>, List<int>> {
class Ascii85Encoder extends Converter<Uint8List, Uint8List> {
@override
List<int> convert(List<int> input) {
Uint8List convert(Uint8List input) {
final Uint8List output = Uint8List(_maxEncodedLen(input.length) + 2);
int outputOffset = 0;
... ...
... ... @@ -35,7 +35,7 @@ abstract class PdfDataType {
return String.fromCharCodes(toStream().output());
}
List<int> toList() {
Uint8List toList() {
return toStream().output();
}
}
... ... @@ -153,8 +153,8 @@ class PdfSecString extends PdfString {
return super.output(s);
}
final List<int> enc = object.pdfDocument.encryption.encrypt(value, object);
_output(s, Uint8List.fromList(enc));
final Uint8List enc = object.pdfDocument.encryption.encrypt(value, object);
_output(s, enc);
}
}
... ...
... ... @@ -116,14 +116,14 @@ class PdfDocument {
final Set<PdfFont> fonts = <PdfFont>{};
/// Generates the document ID
List<int> _documentID;
List<int> get documentID {
Uint8List _documentID;
Uint8List get documentID {
if (_documentID == null) {
final math.Random rnd = math.Random();
_documentID = sha256
_documentID = Uint8List.fromList(sha256
.convert(DateTime.now().toIso8601String().codeUnits +
List<int>.generate(32, (_) => rnd.nextInt(256)))
.bytes;
.bytes);
}
return _documentID;
... ... @@ -182,7 +182,7 @@ class PdfDocument {
pos.close();
}
List<int> save() {
Uint8List save() {
final PdfStream os = PdfStream();
_write(os);
return os.output();
... ...
... ... @@ -19,5 +19,5 @@ part of pdf;
abstract class PdfEncryption extends PdfObject {
PdfEncryption(PdfDocument pdfDocument) : super(pdfDocument, null);
List<int> encrypt(List<int> input, PdfObject object);
Uint8List encrypt(Uint8List input, PdfObject object);
}
... ...
... ... @@ -35,7 +35,7 @@ class PdfObjectStream extends PdfObject {
/// defines if the stream needs to be converted to ascii85
final bool isBinary;
List<int> _data;
Uint8List _data;
@override
void _prepare() {
... ...
... ... @@ -20,30 +20,53 @@ part of pdf;
class PdfStream {
static const int precision = 5;
final List<int> _stream = <int>[];
static const int _grow = 65536;
Uint8List _stream = Uint8List(_grow);
int _offset = 0;
void _ensureCapacity(int size) {
if (_stream.length - _offset >= size) {
return;
}
final int newSize = math.max(_offset + size + _grow, _offset * 2);
final Uint8List newBuffer = Uint8List(newSize);
newBuffer.setAll(0, _stream);
_stream = newBuffer;
}
void putByte(int s) {
_ensureCapacity(1);
_stream[_offset++] = s;
}
void putBytes(List<int> s) {
_ensureCapacity(s.length);
_stream.setAll(_offset, s);
_offset += s.length;
}
void putStream(PdfStream s) {
_stream.addAll(s._stream);
putBytes(s._stream);
}
int get offset => _offset;
Uint8List output() => _stream.sublist(0, _offset);
void putString(String s) {
for (int codeUnit in s.codeUnits) {
if (codeUnit <= 0x7f) {
_stream.add(codeUnit);
putByte(codeUnit);
} else {
_stream.add(0x20);
putByte(0x20);
}
}
}
void putByte(int s) {
_stream.add(s);
}
void putBytes(List<int> s) {
_stream.addAll(s);
}
void putNum(double d) {
assert(d != double.infinity);
putString(d.toStringAsFixed(precision));
... ... @@ -62,44 +85,40 @@ class PdfStream {
for (int c in s) {
switch (c) {
case 0x0a: // \n Line feed (LF)
_stream.add(0x5c);
_stream.add(0x6e);
putByte(0x5c);
putByte(0x6e);
break;
case 0x0d: // \r Carriage return (CR)
_stream.add(0x5c);
_stream.add(0x72);
putByte(0x5c);
putByte(0x72);
break;
case 0x09: // \t Horizontal tab (HT)
_stream.add(0x5c);
_stream.add(0x74);
putByte(0x5c);
putByte(0x74);
break;
case 0x08: // \b Backspace (BS)
_stream.add(0x5c);
_stream.add(0x62);
putByte(0x5c);
putByte(0x62);
break;
case 0x0c: // \f Form feed (FF)
_stream.add(0x5c);
_stream.add(0x66);
putByte(0x5c);
putByte(0x66);
break;
case 0x28: // \( Left parenthesis
_stream.add(0x5c);
_stream.add(0x28);
putByte(0x5c);
putByte(0x28);
break;
case 0x29: // \) Right parenthesis
_stream.add(0x5c);
_stream.add(0x29);
putByte(0x5c);
putByte(0x29);
break;
case 0x5c: // \\ Backslash
_stream.add(0x5c);
_stream.add(0x5c);
putByte(0x5c);
putByte(0x5c);
break;
default:
_stream.add(c);
putByte(c);
}
}
}
int get offset => _stream.length;
List<int> output() => _stream;
}
... ...
... ... @@ -66,7 +66,7 @@ class Document {
_pages.add(page);
}
List<int> save() {
Uint8List save() {
if (!_paint) {
for (Page page in _pages) {
page.postProcess(this);
... ...
... ... @@ -61,7 +61,7 @@ void main() {
final ReceivePort receivePort = ReceivePort();
receivePort.listen((dynamic data) async {
if (data is List<int>) {
if (data is Uint8List) {
print('Received a ${data.length} bytes PDF');
final File file = File('isolate.pdf');
await file.writeAsBytes(data);
... ...
... ... @@ -9,6 +9,7 @@
- Add Unit tests
- Update example tab
- Uniformize examples
- Optimize memory footprint
## 3.1.0
... ...
... ... @@ -15,9 +15,10 @@
*/
import 'dart:async';
import 'dart:typed_data';
import 'package:pdf/pdf.dart';
/// Callback used to generate the Pdf document dynamically when the user
/// changes the page settings: size and margins
typedef LayoutCallback = FutureOr<List<int>> Function(PdfPageFormat format);
typedef LayoutCallback = FutureOr<Uint8List> Function(PdfPageFormat format);
... ...
... ... @@ -15,6 +15,7 @@
*/
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/rendering.dart' show Rect;
import 'package:pdf/pdf.dart';
... ... @@ -81,13 +82,13 @@ abstract class PrintingPlatform extends PlatformInterface {
/// Displays a platform popup to share the Pdf document to another application
Future<bool> sharePdf(
List<int> bytes,
Uint8List bytes,
String filename,
Rect bounds,
);
/// Convert an html document to a pdf data
Future<List<int>> convertHtml(
Future<Uint8List> convertHtml(
String html,
String baseUrl,
PdfPageFormat format,
... ... @@ -95,7 +96,7 @@ abstract class PrintingPlatform extends PlatformInterface {
/// Convert a Pdf document to bitmap images
Stream<PdfRaster> raster(
List<int> document,
Uint8List document,
List<int> pages,
double dpi,
);
... ...
... ... @@ -54,7 +54,7 @@ class MethodChannelPrinting extends PrintingPlatform {
marginBottom: call.arguments['marginBottom'],
);
final List<int> bytes = await job.onLayout(format);
final Uint8List bytes = await job.onLayout(format);
if (bytes == null) {
throw 'onLayout returned null';
... ... @@ -186,7 +186,7 @@ class MethodChannelPrinting extends PrintingPlatform {
onCompleted: Completer<bool>(),
));
final List<int> bytes = await onLayout(format);
final Uint8List bytes = await onLayout(format);
if (bytes == null) {
return false;
}
... ... @@ -205,7 +205,7 @@ class MethodChannelPrinting extends PrintingPlatform {
@override
Future<bool> sharePdf(
List<int> bytes,
Uint8List bytes,
String filename,
Rect bounds,
) async {
... ... @@ -221,10 +221,10 @@ class MethodChannelPrinting extends PrintingPlatform {
}
@override
Future<List<int>> convertHtml(
Future<Uint8List> convertHtml(
String html, String baseUrl, PdfPageFormat format) async {
final PrintJob job = _newPrintJob(PrintJob(
onHtmlRendered: Completer<List<int>>(),
onHtmlRendered: Completer<Uint8List>(),
));
final Map<String, dynamic> params = <String, dynamic>{
... ... @@ -240,14 +240,14 @@ class MethodChannelPrinting extends PrintingPlatform {
};
await _channel.invokeMethod<void>('convertHtml', params);
final List<int> result = await job.onHtmlRendered.future;
final Uint8List result = await job.onHtmlRendered.future;
_printJobs.remove(job.index);
return result;
}
@override
Stream<PdfRaster> raster(
List<int> document,
Uint8List document,
List<int> pages,
double dpi,
) {
... ...
... ... @@ -15,6 +15,7 @@
*/
import 'dart:async';
import 'dart:typed_data';
import 'callback.dart';
import 'raster.dart';
... ... @@ -28,7 +29,7 @@ class PrintJob {
});
final LayoutCallback onLayout;
final Completer<List<int>> onHtmlRendered;
final Completer<Uint8List> onHtmlRendered;
final Completer<bool> onCompleted;
final StreamController<PdfRaster> onPageRasterized;
... ...
... ... @@ -15,6 +15,7 @@
*/
import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/rendering.dart' show Rect, Offset;
import 'package:meta/meta.dart';
... ... @@ -83,7 +84,7 @@ mixin Printing {
/// Displays a platform popup to share the Pdf document to another application
static Future<bool> sharePdf({
@Deprecated('use bytes with document.save()') PdfDocument document,
List<int> bytes,
Uint8List bytes,
String filename = 'document.pdf',
Rect bounds,
}) {
... ... @@ -105,7 +106,7 @@ mixin Printing {
}
/// Convert an html document to a pdf data
static Future<List<int>> convertHtml({
static Future<Uint8List> convertHtml({
@required String html,
String baseUrl,
PdfPageFormat format = PdfPageFormat.standard,
... ... @@ -134,7 +135,7 @@ mixin Printing {
}
static Stream<PdfRaster> raster(
List<int> document, {
Uint8List document, {
List<int> pages,
double dpi = PdfPageFormat.inch,
}) {
... ... @@ -150,7 +151,7 @@ mixin Printing {
@Deprecated('use Printing.layoutPdf(onLayout: (_) => document.save());')
static Future<void> printPdf({
@Deprecated('use bytes with document.save()') PdfDocument document,
List<int> bytes,
Uint8List bytes,
}) async {
assert(document != null || bytes != null);
assert(!(document == null && bytes == null));
... ...
... ... @@ -56,7 +56,7 @@ class PrintingPlugin extends PrintingPlatform {
String name,
PdfPageFormat format,
) async {
final List<int> result = await onLayout(format);
final Uint8List result = await onLayout(format);
if (result == null || result.isEmpty) {
return false;
... ... @@ -83,7 +83,7 @@ class PrintingPlugin extends PrintingPlatform {
final String pdfUrl = html.Url.createObjectUrl(pdfFile);
final html.HtmlDocument doc = js.context['document'];
final html.IFrameElement frame =
final html.Element frame =
doc.getElementById(_frameId) ?? doc.createElement('iframe');
frame.setAttribute(
'style',
... ... @@ -112,7 +112,7 @@ class PrintingPlugin extends PrintingPlatform {
@override
Future<bool> sharePdf(
List<int> bytes,
Uint8List bytes,
String filename,
Rect bounds,
) async {
... ... @@ -130,7 +130,7 @@ class PrintingPlugin extends PrintingPlatform {
}
@override
Future<List<int>> convertHtml(
Future<Uint8List> convertHtml(
String html,
String baseUrl,
PdfPageFormat format,
... ... @@ -157,7 +157,7 @@ class PrintingPlugin extends PrintingPlatform {
@override
Stream<PdfRaster> raster(
List<int> document,
Uint8List document,
List<int> pages,
double dpi,
) {
... ...
... ... @@ -15,7 +15,7 @@ dependencies:
sdk: flutter
flutter_web_plugins:
sdk: flutter
pdf: ^1.3.15
pdf: ^1.6.0
plugin_platform_interface: ^1.0.2
dev_dependencies:
... ...
... ... @@ -14,6 +14,8 @@
* limitations under the License.
*/
import 'dart:typed_data';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:pdf/pdf.dart';
... ... @@ -56,7 +58,7 @@ void main() {
expect(
await Printing.sharePdf(
bytes: <int>[],
bytes: Uint8List(0),
),
null,
);
... ... @@ -106,7 +108,7 @@ void main() {
);
expect(
Printing.raster(<int>[]),
Printing.raster(Uint8List(0)),
null,
);
});
... ...