David PHAM-VAN

Add Hyperlink widgets

... ... @@ -5,6 +5,7 @@
* Improve MultiPage Widget
* Convert GridView to a SpanningWidget
* Add all Material Colors
* Add Hyperlink widgets
# 1.3.3
* Fix a bug with the RichText Widget
... ...
... ... @@ -41,6 +41,7 @@ part 'src/formxobject.dart';
part 'src/graphics.dart';
part 'src/image.dart';
part 'src/info.dart';
part 'src/names.dart';
part 'src/object.dart';
part 'src/object_stream.dart';
part 'src/outline.dart';
... ...
... ... @@ -24,7 +24,9 @@ class PdfAnnot extends PdfObject {
@required this.subtype,
this.dest,
this.destRect,
this.border})
this.border,
this.url,
this.name})
: super(pdfPage.pdfDocument, type ?? '/Annot') {
pdfPage.annotations.add(this);
}
... ... @@ -56,6 +58,18 @@ class PdfAnnot extends PdfObject {
destRect: destRect,
border: border);
/// Creates an external link annotation
factory PdfAnnot.urlLink(PdfPage pdfPage,
{@required PdfRect rect, @required String dest, PdfBorder border}) =>
PdfAnnot._create(pdfPage,
subtype: '/Link', srcRect: rect, url: dest, border: border);
/// Creates a link annotation to a named destination
factory PdfAnnot.namedLink(PdfPage pdfPage,
{@required PdfRect rect, @required String dest, PdfBorder border}) =>
PdfAnnot._create(pdfPage,
subtype: '/Link', srcRect: rect, name: dest, border: border);
/// The subtype of the outline, ie text, note, etc
final String subtype;
... ... @@ -75,6 +89,12 @@ class PdfAnnot extends PdfObject {
/// the border for this annotation
final PdfBorder border;
/// The external url for a link
final String url;
/// The internal name for a link
final String name;
/// Output the annotation
///
/// @param os OutputStream to send the object to
... ... @@ -83,8 +103,9 @@ class PdfAnnot extends PdfObject {
super._prepare();
params['/Subtype'] = PdfStream.string(subtype);
params['/Rect'] = PdfStream.string(
'[${srcRect.left} ${srcRect.bottom} ${srcRect.right} ${srcRect.top}]');
params['/Rect'] = PdfStream()
..putNumArray(
<double>[srcRect.left, srcRect.bottom, srcRect.right, srcRect.top]);
// handle the border
if (border == null) {
... ... @@ -97,15 +118,35 @@ class PdfAnnot extends PdfObject {
if (subtype == '/Text') {
params['/Contents'] = PdfStream()..putLiteral(content);
} else if (subtype == '/Link') {
if (url != null) {
params['/A'] = PdfStream()
..putDictionary(<String, PdfStream>{
'/S': PdfStream()..putString('/URI'),
'/URI': PdfStream()..putText(url),
});
} else if (name != null) {
params['/A'] = PdfStream()
..putDictionary(<String, PdfStream>{
'/S': PdfStream()..putString('/GoTo'),
'/D': PdfStream()..putText(name),
});
} else {
final List<PdfStream> dests = <PdfStream>[];
dests.add(dest.ref());
if (destRect == null)
dests.add(PdfStream.string('/Fit'));
else {
dests.add(PdfStream.string(
'/FitR ${destRect.left} ${destRect.bottom} ${destRect.right} ${destRect.top}'));
dests.add(PdfStream.string('/FitR '));
dests.add(PdfStream()
..putNumList(<double>[
destRect.left,
destRect.bottom,
destRect.right,
destRect.top
]));
}
params['/Dest'] = PdfStream.array(dests);
}
}
}
}
... ...
... ... @@ -22,7 +22,8 @@ class PdfCatalog extends PdfObject {
/// @param pdfPageList The [PdfPageList] object that's the root of the documents page tree
/// @param pagemode How the document should appear when opened.
/// Allowed values are usenone, useoutlines, usethumbs or fullscreen.
PdfCatalog(PdfDocument pdfDocument, this.pdfPageList, this.pageMode)
PdfCatalog(
PdfDocument pdfDocument, this.pdfPageList, this.pageMode, this.names)
: super(pdfDocument, '/Catalog');
/// The pages of the document
... ... @@ -34,6 +35,9 @@ class PdfCatalog extends PdfObject {
/// The initial page mode
final PdfPageMode pageMode;
/// The initial page mode
final PdfNames names;
/// @param os OutputStream to send the object to
@override
void _prepare() {
... ... @@ -46,6 +50,9 @@ class PdfCatalog extends PdfObject {
params['/Outlines'] = outlines.ref();
}
// the Names object
params['/Names'] = names.ref();
// the /PageMode setting
params['/PageMode'] =
PdfStream.string(PdfDocument._PdfPageModes[pageMode.index]);
... ...
... ... @@ -89,9 +89,9 @@ class PDFBorder extends PdfBorder {
@deprecated
class PDFCatalog extends PdfCatalog {
PDFCatalog(
PdfDocument pdfDocument, PdfPageList pdfPageList, PdfPageMode pageMode)
: super(pdfDocument, pdfPageList, pageMode);
PDFCatalog(PdfDocument pdfDocument, PdfPageList pdfPageList,
PdfPageMode pageMode, PdfNames names)
: super(pdfDocument, pdfPageList, pageMode, names);
}
@deprecated
... ...
... ... @@ -51,7 +51,8 @@ class PdfDocument {
// Now create some standard objects
pdfPageList = PdfPageList(this);
catalog = PdfCatalog(this, pdfPageList, pageMode);
pdfNames = PdfNames(this);
catalog = PdfCatalog(this, pdfPageList, pageMode, pdfNames);
}
/// This is used to allocate objects a unique serial number in the document.
... ... @@ -70,6 +71,9 @@ class PdfDocument {
/// This is the Pages object, which is required by each Pdf Document
PdfPageList pdfPageList;
/// The name dictionary
PdfNames pdfNames;
/// This is the Outline object, which is optional
PdfOutline _outline;
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of pdf;
class PdfNames extends PdfObject {
/// This constructs a Pdf Name object
PdfNames(PdfDocument pdfDocument) : super(pdfDocument);
final List<PdfStream> _dests = <PdfStream>[];
void addDest(
String name,
PdfPage page, {
double posX,
double posY,
double posZ,
}) {
assert(page.pdfDocument == pdfDocument);
assert(name != null);
_dests.add(PdfStream()..putText(name));
_dests.add(PdfStream()
..putDictionary(<String, PdfStream>{
'/D': PdfStream()
..putArray(<PdfStream>[
page.ref(),
PdfStream.string('/XYZ'),
posX == null ? PdfStream.string('null') : PdfStream.num(posX),
posY == null ? PdfStream.string('null') : PdfStream.num(posY),
posZ == null ? PdfStream.string('null') : PdfStream.num(posZ),
]),
}));
}
@override
void _prepare() {
super._prepare();
params['/Dests'] = PdfStream()
..putDictionary(<String, PdfStream>{
'/Names': PdfStream()..putArray(_dests),
});
}
}
... ...
... ... @@ -23,6 +23,7 @@ import 'package:meta/meta.dart';
import 'package:pdf/pdf.dart';
import 'package:vector_math/vector_math_64.dart';
part 'widgets/annotations.dart';
part 'widgets/basic.dart';
part 'widgets/clip.dart';
part 'widgets/container.dart';
... ...
/*
* Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
part of widget;
class Anchor extends SingleChildWidget {
Anchor({Widget child, @required this.name, this.description})
: assert(name != null),
super(child: child);
final String name;
final String description;
@override
void paint(Context context) {
super.paint(context);
paintChild(context);
final Matrix4 mat = context.canvas.getTransform();
final Vector3 lt = mat.transform3(Vector3(box.left, box.bottom, 0));
context.document.pdfNames.addDest(name, context.page, posY: lt.y);
if (description != null) {
final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0));
final PdfRect ibox = PdfRect.fromLTRB(lt.x, lt.y, rb.x, rb.y);
PdfAnnot.text(context.page, content: description, rect: ibox);
}
}
}
class _Annotation extends SingleChildWidget {
_Annotation({Widget child}) : super(child: child);
@override
void debugPaint(Context context) {
context.canvas
..setFillColor(PdfColors.pink)
..drawRect(box.x, box.y, box.width, box.height)
..fillPath();
}
@override
void paint(Context context) {
super.paint(context);
paintChild(context);
}
}
class Link extends _Annotation {
Link({@required Widget child, this.destination})
: assert(child != null),
super(child: child);
final String destination;
@override
void paint(Context context) {
super.paint(context);
if (destination != null) {
final Matrix4 mat = context.canvas.getTransform();
final Vector3 lt = mat.transform3(Vector3(box.left, box.bottom, 0));
final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0));
final PdfRect ibox = PdfRect.fromLTRB(lt.x, lt.y, rb.x, rb.y);
PdfAnnot.namedLink(
context.page,
rect: ibox,
dest: destination,
);
}
}
}
class UrlLink extends _Annotation {
UrlLink({@required Widget child, @required this.destination})
: assert(child != null),
assert(destination != null),
super(child: child);
final String destination;
@override
void paint(Context context) {
super.paint(context);
final Matrix4 mat = context.canvas.getTransform();
final Vector3 lt = mat.transform3(Vector3(box.left, box.bottom, 0));
final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0));
final PdfRect ibox = PdfRect.fromLTRB(lt.x, lt.y, rb.x, rb.y);
PdfAnnot.urlLink(
context.page,
rect: ibox,
dest: destination,
);
}
}
... ...
... ... @@ -36,6 +36,12 @@ void main() {
g.drawRect(100, 150, 50, 50);
g.strokePath();
PdfAnnot.urlLink(page,
rect: const PdfRect(100, 250, 50, 50),
dest: 'https://github.com/DavBfr/dart_pdf/');
g.drawRect(100, 250, 50, 50);
g.strokePath();
final File file = File('annotations.pdf');
file.writeAsBytesSync(pdf.save());
});
... ...
... ... @@ -51,7 +51,10 @@ void main() {
width: 2)),
child: Text('Hello World',
textScaleFactor: 2, textAlign: TextAlign.center)),
Align(alignment: Alignment.topLeft, child: Text('Left align')),
Align(
alignment: Alignment.topLeft,
child:
Link(destination: 'anchor', child: Text('Left align'))),
Padding(padding: const EdgeInsets.all(5)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
... ... @@ -133,6 +136,7 @@ void main() {
<String>['York Steak House', 'Outi Vuorinen', 'Finland'],
<String>['Weathervane', 'Else Jeremiassen', 'Iceland'],
]),
Anchor(name: 'anchor', child: Text('Anchor')),
]));
pdf.addPage(Page(
... ... @@ -172,7 +176,13 @@ void main() {
),
],
),
))
)),
Positioned(
right: 10,
bottom: 10,
child: UrlLink(
child: Text('dart_pdf'),
destination: 'https://github.com/DavBfr/dart_pdf/'))
])));
final File file = File('widgets.pdf');
... ...