David PHAM-VAN

Implement Image orientation

... ... @@ -14,6 +14,7 @@
- Add Ascii85 test
- Add more warnings on type1 fonts
- Simplify PdfImage constructor
- Implement Image orientation
## 1.3.23
... ...
... ... @@ -200,7 +200,13 @@ class PDFImage extends PdfImage {
@required int height,
bool alpha = true,
}) : super._(pdfDocument,
image: image, width: width, height: height, alpha: alpha);
image: image,
width: width,
height: height,
alpha: alpha,
alphaChannel: false,
jpeg: false,
orientation: PdfImageOrientation.topLeft);
}
@deprecated
... ...
... ... @@ -108,7 +108,33 @@ class PdfGraphics {
// q w 0 0 h x y cm % the coordinate matrix
buf.putString('q ');
buf.putNumList(<double>[w, 0, 0, h, x, y]);
switch (img.orientation) {
case PdfImageOrientation.topLeft:
buf.putNumList(<double>[w, 0, 0, h, x, y]);
break;
case PdfImageOrientation.topRight:
buf.putNumList(<double>[-w, 0, 0, h, w - x, y]);
break;
case PdfImageOrientation.bottomRight:
buf.putNumList(<double>[-w, 0, 0, -h, w - x, h - y]);
break;
case PdfImageOrientation.bottomLeft:
buf.putNumList(<double>[w, 0, 0, -h, x, h - y]);
break;
case PdfImageOrientation.leftTop:
buf.putNumList(<double>[0, -h, -w, 0, w - x, h - y]);
break;
case PdfImageOrientation.rightTop:
buf.putNumList(<double>[0, h, -w, 0, w - x, y]);
break;
case PdfImageOrientation.rightBottom:
buf.putNumList(<double>[0, h, w, 0, x, y]);
break;
case PdfImageOrientation.leftBottom:
buf.putNumList(<double>[0, -h, w, 0, x, h - y]);
break;
}
buf.putString(' cm ${img.name} Do Q\n');
}
... ...
... ... @@ -16,6 +16,19 @@
part of pdf;
/// Represents the position of the first pixel in the data stream
/// This corresponds to the exif orientations
enum PdfImageOrientation {
topLeft,
topRight,
bottomRight,
bottomLeft,
leftTop,
rightTop,
rightBottom,
leftBottom,
}
class PdfImage extends PdfXObject {
/// Creates a new [PdfImage] instance.
///
... ... @@ -29,6 +42,7 @@ class PdfImage extends PdfXObject {
@required int width,
@required int height,
bool alpha = true,
PdfImageOrientation orientation = PdfImageOrientation.topLeft,
}) =>
PdfImage._(
pdfDocument,
... ... @@ -36,18 +50,27 @@ class PdfImage extends PdfXObject {
width: width,
height: height,
alpha: alpha,
alphaChannel: false,
jpeg: false,
orientation: orientation,
);
PdfImage._(PdfDocument pdfDocument,
{@required this.image,
@required this.width,
@required this.height,
this.alpha = true,
this.alphaChannel = false,
this.jpeg = false})
: assert(alphaChannel == false || alpha == true),
PdfImage._(
PdfDocument pdfDocument, {
@required this.image,
@required int width,
@required int height,
@required this.alpha,
@required this.alphaChannel,
@required this.jpeg,
@required this.orientation,
}) : assert(alphaChannel == false || alpha == true),
assert(width != null),
assert(height != null),
assert(jpeg != null),
assert(orientation != null),
_width = width,
_height = height,
super(pdfDocument, '/Image', isBinary: true) {
_name = '/Image$objser';
params['/Width'] = PdfStream.string(width.toString());
... ... @@ -56,12 +79,16 @@ class PdfImage extends PdfXObject {
params['/Name'] = PdfStream.string(_name);
if (alphaChannel == false && alpha) {
final PdfImage _sMask = PdfImage._(pdfDocument,
image: image,
width: width,
height: height,
alpha: alpha,
alphaChannel: true);
final PdfImage _sMask = PdfImage._(
pdfDocument,
image: image,
width: width,
height: height,
alpha: alpha,
alphaChannel: true,
jpeg: jpeg,
orientation: orientation,
);
params['/SMask'] = PdfStream.string('${_sMask.objser} 0 R');
}
... ... @@ -76,7 +103,11 @@ class PdfImage extends PdfXObject {
}
}
factory PdfImage.jpeg(PdfDocument pdfDocument, {@required Uint8List image}) {
factory PdfImage.jpeg(
PdfDocument pdfDocument, {
@required Uint8List image,
PdfImageOrientation orientation,
}) {
assert(image != null);
int width;
... ... @@ -117,18 +148,30 @@ class PdfImage extends PdfXObject {
offset += len - 2;
}
return PdfImage._(pdfDocument,
image: image, width: width, height: height, jpeg: true, alpha: false);
orientation ??= PdfImageOrientation.leftTop;
return PdfImage._(
pdfDocument,
image: image,
width: width,
height: height,
jpeg: true,
alpha: false,
alphaChannel: false,
orientation: orientation,
);
}
/// RGBA Image Data
final Uint8List image;
/// Image width
final int width;
final int _width;
int get width => orientation.index >= 4 ? _height : _width;
/// Image height
final int height;
final int _height;
int get height => orientation.index < 4 ? _height : _width;
/// Image has alpha channel
final bool alpha;
... ... @@ -141,6 +184,9 @@ class PdfImage extends PdfXObject {
/// The image data is a jpeg image
final bool jpeg;
/// The internal orientation of the image
final PdfImageOrientation orientation;
/// write the pixels to the stream
@override
void _prepare() {
... ... @@ -151,8 +197,8 @@ class PdfImage extends PdfXObject {
return;
}
final int w = width;
final int h = height;
final int w = _width;
final int h = _height;
final int s = w * h;
final Uint8List out = Uint8List(alphaChannel ? s : s * 3);
... ...
... ... @@ -15,36 +15,73 @@
*/
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart';
import 'package:test/test.dart';
Future<Uint8List> download(String url) async {
final HttpClient client = HttpClient();
final HttpClientRequest request = await client.getUrl(Uri.parse(url));
final HttpClientResponse response = await request.close();
final BytesBuilder builder = await response.fold(
BytesBuilder(), (BytesBuilder b, List<int> d) => b..add(d));
final List<int> data = builder.takeBytes();
return Uint8List.fromList(data);
}
Document pdf;
void main() {
test('Pdf Jpeg', () async {
final PdfDocument pdf = PdfDocument();
final PdfPage page = PdfPage(pdf, pageFormat: PdfPageFormat.a4);
setUpAll(() {
Document.debug = true;
pdf = Document();
});
test('Pdf Jpeg Download', () async {
final PdfImage image = PdfImage.jpeg(
pdf,
pdf.document,
image: await download('https://www.nfet.net/nfet.jpg'),
);
final PdfGraphics g = page.getGraphics();
g.drawImage(image, 30, page.pageFormat.height - 507.0);
pdf.addPage(Page(
build: (Context context) => Center(child: Image(image)),
));
});
test('Pdf Jpeg Orientation', () {
pdf.addPage(
Page(
build: (Context context) => Wrap(
spacing: 20,
runSpacing: 20,
children: List<Widget>.generate(
PdfImageOrientation.values.length,
(int index) => SizedBox(
width: 230,
height: 230,
child: Image(
PdfImage.jpeg(
pdf.document,
image: base64.decode(jpegImage),
orientation: PdfImageOrientation.values[index],
),
),
),
),
),
),
);
});
tearDownAll(() {
final File file = File('jpeg.pdf');
file.writeAsBytesSync(pdf.save());
});
}
Future<Uint8List> download(String url) async {
final HttpClient client = HttpClient();
final HttpClientRequest request = await client.getUrl(Uri.parse(url));
final HttpClientResponse response = await request.close();
final BytesBuilder builder = await response.fold(
BytesBuilder(), (BytesBuilder b, List<int> d) => b..add(d));
final List<int> data = builder.takeBytes();
return Uint8List.fromList(data);
}
const String jpegImage =
'/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAEMuMjoyKkM6NjpLR0NPZKZsZFxcZMySmnmm8dT++u3U6eX//////////+Xp////////////////////////////2wBDAUdLS2RXZMRsbMT//+n/////////////////////////////////////////////////////////////////////wAARCAAUAAgDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAP/xAAbEAACAwEBAQAAAAAAAAAAAAABAgARIQMEQf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCvm5joGZi1hj9iPIgIZ7Nhzl5EC3FAikC9N7ERA//Z';
... ...