Showing
5 changed files
with
149 additions
and
33 deletions
| @@ -200,7 +200,13 @@ class PDFImage extends PdfImage { | @@ -200,7 +200,13 @@ class PDFImage extends PdfImage { | ||
| 200 | @required int height, | 200 | @required int height, |
| 201 | bool alpha = true, | 201 | bool alpha = true, |
| 202 | }) : super._(pdfDocument, | 202 | }) : super._(pdfDocument, |
| 203 | - image: image, width: width, height: height, alpha: alpha); | 203 | + image: image, |
| 204 | + width: width, | ||
| 205 | + height: height, | ||
| 206 | + alpha: alpha, | ||
| 207 | + alphaChannel: false, | ||
| 208 | + jpeg: false, | ||
| 209 | + orientation: PdfImageOrientation.topLeft); | ||
| 204 | } | 210 | } |
| 205 | 211 | ||
| 206 | @deprecated | 212 | @deprecated |
| @@ -108,7 +108,33 @@ class PdfGraphics { | @@ -108,7 +108,33 @@ class PdfGraphics { | ||
| 108 | 108 | ||
| 109 | // q w 0 0 h x y cm % the coordinate matrix | 109 | // q w 0 0 h x y cm % the coordinate matrix |
| 110 | buf.putString('q '); | 110 | buf.putString('q '); |
| 111 | + switch (img.orientation) { | ||
| 112 | + case PdfImageOrientation.topLeft: | ||
| 111 | buf.putNumList(<double>[w, 0, 0, h, x, y]); | 113 | buf.putNumList(<double>[w, 0, 0, h, x, y]); |
| 114 | + break; | ||
| 115 | + case PdfImageOrientation.topRight: | ||
| 116 | + buf.putNumList(<double>[-w, 0, 0, h, w - x, y]); | ||
| 117 | + break; | ||
| 118 | + case PdfImageOrientation.bottomRight: | ||
| 119 | + buf.putNumList(<double>[-w, 0, 0, -h, w - x, h - y]); | ||
| 120 | + break; | ||
| 121 | + case PdfImageOrientation.bottomLeft: | ||
| 122 | + buf.putNumList(<double>[w, 0, 0, -h, x, h - y]); | ||
| 123 | + break; | ||
| 124 | + case PdfImageOrientation.leftTop: | ||
| 125 | + buf.putNumList(<double>[0, -h, -w, 0, w - x, h - y]); | ||
| 126 | + break; | ||
| 127 | + case PdfImageOrientation.rightTop: | ||
| 128 | + buf.putNumList(<double>[0, h, -w, 0, w - x, y]); | ||
| 129 | + break; | ||
| 130 | + case PdfImageOrientation.rightBottom: | ||
| 131 | + buf.putNumList(<double>[0, h, w, 0, x, y]); | ||
| 132 | + break; | ||
| 133 | + case PdfImageOrientation.leftBottom: | ||
| 134 | + buf.putNumList(<double>[0, -h, w, 0, x, h - y]); | ||
| 135 | + break; | ||
| 136 | + } | ||
| 137 | + | ||
| 112 | buf.putString(' cm ${img.name} Do Q\n'); | 138 | buf.putString(' cm ${img.name} Do Q\n'); |
| 113 | } | 139 | } |
| 114 | 140 |
| @@ -16,6 +16,19 @@ | @@ -16,6 +16,19 @@ | ||
| 16 | 16 | ||
| 17 | part of pdf; | 17 | part of pdf; |
| 18 | 18 | ||
| 19 | +/// Represents the position of the first pixel in the data stream | ||
| 20 | +/// This corresponds to the exif orientations | ||
| 21 | +enum PdfImageOrientation { | ||
| 22 | + topLeft, | ||
| 23 | + topRight, | ||
| 24 | + bottomRight, | ||
| 25 | + bottomLeft, | ||
| 26 | + leftTop, | ||
| 27 | + rightTop, | ||
| 28 | + rightBottom, | ||
| 29 | + leftBottom, | ||
| 30 | +} | ||
| 31 | + | ||
| 19 | class PdfImage extends PdfXObject { | 32 | class PdfImage extends PdfXObject { |
| 20 | /// Creates a new [PdfImage] instance. | 33 | /// Creates a new [PdfImage] instance. |
| 21 | /// | 34 | /// |
| @@ -29,6 +42,7 @@ class PdfImage extends PdfXObject { | @@ -29,6 +42,7 @@ class PdfImage extends PdfXObject { | ||
| 29 | @required int width, | 42 | @required int width, |
| 30 | @required int height, | 43 | @required int height, |
| 31 | bool alpha = true, | 44 | bool alpha = true, |
| 45 | + PdfImageOrientation orientation = PdfImageOrientation.topLeft, | ||
| 32 | }) => | 46 | }) => |
| 33 | PdfImage._( | 47 | PdfImage._( |
| 34 | pdfDocument, | 48 | pdfDocument, |
| @@ -36,18 +50,27 @@ class PdfImage extends PdfXObject { | @@ -36,18 +50,27 @@ class PdfImage extends PdfXObject { | ||
| 36 | width: width, | 50 | width: width, |
| 37 | height: height, | 51 | height: height, |
| 38 | alpha: alpha, | 52 | alpha: alpha, |
| 53 | + alphaChannel: false, | ||
| 54 | + jpeg: false, | ||
| 55 | + orientation: orientation, | ||
| 39 | ); | 56 | ); |
| 40 | 57 | ||
| 41 | - PdfImage._(PdfDocument pdfDocument, | ||
| 42 | - {@required this.image, | ||
| 43 | - @required this.width, | ||
| 44 | - @required this.height, | ||
| 45 | - this.alpha = true, | ||
| 46 | - this.alphaChannel = false, | ||
| 47 | - this.jpeg = false}) | ||
| 48 | - : assert(alphaChannel == false || alpha == true), | 58 | + PdfImage._( |
| 59 | + PdfDocument pdfDocument, { | ||
| 60 | + @required this.image, | ||
| 61 | + @required int width, | ||
| 62 | + @required int height, | ||
| 63 | + @required this.alpha, | ||
| 64 | + @required this.alphaChannel, | ||
| 65 | + @required this.jpeg, | ||
| 66 | + @required this.orientation, | ||
| 67 | + }) : assert(alphaChannel == false || alpha == true), | ||
| 49 | assert(width != null), | 68 | assert(width != null), |
| 50 | assert(height != null), | 69 | assert(height != null), |
| 70 | + assert(jpeg != null), | ||
| 71 | + assert(orientation != null), | ||
| 72 | + _width = width, | ||
| 73 | + _height = height, | ||
| 51 | super(pdfDocument, '/Image', isBinary: true) { | 74 | super(pdfDocument, '/Image', isBinary: true) { |
| 52 | _name = '/Image$objser'; | 75 | _name = '/Image$objser'; |
| 53 | params['/Width'] = PdfStream.string(width.toString()); | 76 | params['/Width'] = PdfStream.string(width.toString()); |
| @@ -56,12 +79,16 @@ class PdfImage extends PdfXObject { | @@ -56,12 +79,16 @@ class PdfImage extends PdfXObject { | ||
| 56 | params['/Name'] = PdfStream.string(_name); | 79 | params['/Name'] = PdfStream.string(_name); |
| 57 | 80 | ||
| 58 | if (alphaChannel == false && alpha) { | 81 | if (alphaChannel == false && alpha) { |
| 59 | - final PdfImage _sMask = PdfImage._(pdfDocument, | 82 | + final PdfImage _sMask = PdfImage._( |
| 83 | + pdfDocument, | ||
| 60 | image: image, | 84 | image: image, |
| 61 | width: width, | 85 | width: width, |
| 62 | height: height, | 86 | height: height, |
| 63 | alpha: alpha, | 87 | alpha: alpha, |
| 64 | - alphaChannel: true); | 88 | + alphaChannel: true, |
| 89 | + jpeg: jpeg, | ||
| 90 | + orientation: orientation, | ||
| 91 | + ); | ||
| 65 | params['/SMask'] = PdfStream.string('${_sMask.objser} 0 R'); | 92 | params['/SMask'] = PdfStream.string('${_sMask.objser} 0 R'); |
| 66 | } | 93 | } |
| 67 | 94 | ||
| @@ -76,7 +103,11 @@ class PdfImage extends PdfXObject { | @@ -76,7 +103,11 @@ class PdfImage extends PdfXObject { | ||
| 76 | } | 103 | } |
| 77 | } | 104 | } |
| 78 | 105 | ||
| 79 | - factory PdfImage.jpeg(PdfDocument pdfDocument, {@required Uint8List image}) { | 106 | + factory PdfImage.jpeg( |
| 107 | + PdfDocument pdfDocument, { | ||
| 108 | + @required Uint8List image, | ||
| 109 | + PdfImageOrientation orientation, | ||
| 110 | + }) { | ||
| 80 | assert(image != null); | 111 | assert(image != null); |
| 81 | 112 | ||
| 82 | int width; | 113 | int width; |
| @@ -117,18 +148,30 @@ class PdfImage extends PdfXObject { | @@ -117,18 +148,30 @@ class PdfImage extends PdfXObject { | ||
| 117 | offset += len - 2; | 148 | offset += len - 2; |
| 118 | } | 149 | } |
| 119 | 150 | ||
| 120 | - return PdfImage._(pdfDocument, | ||
| 121 | - image: image, width: width, height: height, jpeg: true, alpha: false); | 151 | + orientation ??= PdfImageOrientation.leftTop; |
| 152 | + | ||
| 153 | + return PdfImage._( | ||
| 154 | + pdfDocument, | ||
| 155 | + image: image, | ||
| 156 | + width: width, | ||
| 157 | + height: height, | ||
| 158 | + jpeg: true, | ||
| 159 | + alpha: false, | ||
| 160 | + alphaChannel: false, | ||
| 161 | + orientation: orientation, | ||
| 162 | + ); | ||
| 122 | } | 163 | } |
| 123 | 164 | ||
| 124 | /// RGBA Image Data | 165 | /// RGBA Image Data |
| 125 | final Uint8List image; | 166 | final Uint8List image; |
| 126 | 167 | ||
| 127 | /// Image width | 168 | /// Image width |
| 128 | - final int width; | 169 | + final int _width; |
| 170 | + int get width => orientation.index >= 4 ? _height : _width; | ||
| 129 | 171 | ||
| 130 | /// Image height | 172 | /// Image height |
| 131 | - final int height; | 173 | + final int _height; |
| 174 | + int get height => orientation.index < 4 ? _height : _width; | ||
| 132 | 175 | ||
| 133 | /// Image has alpha channel | 176 | /// Image has alpha channel |
| 134 | final bool alpha; | 177 | final bool alpha; |
| @@ -141,6 +184,9 @@ class PdfImage extends PdfXObject { | @@ -141,6 +184,9 @@ class PdfImage extends PdfXObject { | ||
| 141 | /// The image data is a jpeg image | 184 | /// The image data is a jpeg image |
| 142 | final bool jpeg; | 185 | final bool jpeg; |
| 143 | 186 | ||
| 187 | + /// The internal orientation of the image | ||
| 188 | + final PdfImageOrientation orientation; | ||
| 189 | + | ||
| 144 | /// write the pixels to the stream | 190 | /// write the pixels to the stream |
| 145 | @override | 191 | @override |
| 146 | void _prepare() { | 192 | void _prepare() { |
| @@ -151,8 +197,8 @@ class PdfImage extends PdfXObject { | @@ -151,8 +197,8 @@ class PdfImage extends PdfXObject { | ||
| 151 | return; | 197 | return; |
| 152 | } | 198 | } |
| 153 | 199 | ||
| 154 | - final int w = width; | ||
| 155 | - final int h = height; | 200 | + final int w = _width; |
| 201 | + final int h = _height; | ||
| 156 | final int s = w * h; | 202 | final int s = w * h; |
| 157 | 203 | ||
| 158 | final Uint8List out = Uint8List(alphaChannel ? s : s * 3); | 204 | final Uint8List out = Uint8List(alphaChannel ? s : s * 3); |
| @@ -15,36 +15,73 @@ | @@ -15,36 +15,73 @@ | ||
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | import 'dart:async'; | 17 | import 'dart:async'; |
| 18 | +import 'dart:convert'; | ||
| 18 | import 'dart:io'; | 19 | import 'dart:io'; |
| 19 | import 'dart:typed_data'; | 20 | import 'dart:typed_data'; |
| 20 | 21 | ||
| 21 | import 'package:pdf/pdf.dart'; | 22 | import 'package:pdf/pdf.dart'; |
| 23 | +import 'package:pdf/widgets.dart'; | ||
| 22 | import 'package:test/test.dart'; | 24 | import 'package:test/test.dart'; |
| 23 | 25 | ||
| 24 | -Future<Uint8List> download(String url) async { | ||
| 25 | - final HttpClient client = HttpClient(); | ||
| 26 | - final HttpClientRequest request = await client.getUrl(Uri.parse(url)); | ||
| 27 | - final HttpClientResponse response = await request.close(); | ||
| 28 | - final BytesBuilder builder = await response.fold( | ||
| 29 | - BytesBuilder(), (BytesBuilder b, List<int> d) => b..add(d)); | ||
| 30 | - final List<int> data = builder.takeBytes(); | ||
| 31 | - return Uint8List.fromList(data); | ||
| 32 | -} | 26 | +Document pdf; |
| 33 | 27 | ||
| 34 | void main() { | 28 | void main() { |
| 35 | - test('Pdf Jpeg', () async { | ||
| 36 | - final PdfDocument pdf = PdfDocument(); | ||
| 37 | - final PdfPage page = PdfPage(pdf, pageFormat: PdfPageFormat.a4); | 29 | + setUpAll(() { |
| 30 | + Document.debug = true; | ||
| 31 | + pdf = Document(); | ||
| 32 | + }); | ||
| 38 | 33 | ||
| 34 | + test('Pdf Jpeg Download', () async { | ||
| 39 | final PdfImage image = PdfImage.jpeg( | 35 | final PdfImage image = PdfImage.jpeg( |
| 40 | - pdf, | 36 | + pdf.document, |
| 41 | image: await download('https://www.nfet.net/nfet.jpg'), | 37 | image: await download('https://www.nfet.net/nfet.jpg'), |
| 42 | ); | 38 | ); |
| 43 | 39 | ||
| 44 | - final PdfGraphics g = page.getGraphics(); | ||
| 45 | - g.drawImage(image, 30, page.pageFormat.height - 507.0); | 40 | + pdf.addPage(Page( |
| 41 | + build: (Context context) => Center(child: Image(image)), | ||
| 42 | + )); | ||
| 43 | + }); | ||
| 46 | 44 | ||
| 45 | + test('Pdf Jpeg Orientation', () { | ||
| 46 | + pdf.addPage( | ||
| 47 | + Page( | ||
| 48 | + build: (Context context) => Wrap( | ||
| 49 | + spacing: 20, | ||
| 50 | + runSpacing: 20, | ||
| 51 | + children: List<Widget>.generate( | ||
| 52 | + PdfImageOrientation.values.length, | ||
| 53 | + (int index) => SizedBox( | ||
| 54 | + width: 230, | ||
| 55 | + height: 230, | ||
| 56 | + child: Image( | ||
| 57 | + PdfImage.jpeg( | ||
| 58 | + pdf.document, | ||
| 59 | + image: base64.decode(jpegImage), | ||
| 60 | + orientation: PdfImageOrientation.values[index], | ||
| 61 | + ), | ||
| 62 | + ), | ||
| 63 | + ), | ||
| 64 | + ), | ||
| 65 | + ), | ||
| 66 | + ), | ||
| 67 | + ); | ||
| 68 | + }); | ||
| 69 | + | ||
| 70 | + tearDownAll(() { | ||
| 47 | final File file = File('jpeg.pdf'); | 71 | final File file = File('jpeg.pdf'); |
| 48 | file.writeAsBytesSync(pdf.save()); | 72 | file.writeAsBytesSync(pdf.save()); |
| 49 | }); | 73 | }); |
| 50 | } | 74 | } |
| 75 | + | ||
| 76 | +Future<Uint8List> download(String url) async { | ||
| 77 | + final HttpClient client = HttpClient(); | ||
| 78 | + final HttpClientRequest request = await client.getUrl(Uri.parse(url)); | ||
| 79 | + final HttpClientResponse response = await request.close(); | ||
| 80 | + final BytesBuilder builder = await response.fold( | ||
| 81 | + BytesBuilder(), (BytesBuilder b, List<int> d) => b..add(d)); | ||
| 82 | + final List<int> data = builder.takeBytes(); | ||
| 83 | + return Uint8List.fromList(data); | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +const String jpegImage = | ||
| 87 | + '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAEMuMjoyKkM6NjpLR0NPZKZsZFxcZMySmnmm8dT++u3U6eX//////////+Xp////////////////////////////2wBDAUdLS2RXZMRsbMT//+n/////////////////////////////////////////////////////////////////////wAARCAAUAAgDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAP/xAAbEAACAwEBAQAAAAAAAAAAAAABAgARIQMEQf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCvm5joGZi1hj9iPIgIZ7Nhzl5EC3FAikC9N7ERA//Z'; |
-
Please register or login to post a comment