Showing
9 changed files
with
445 additions
and
160 deletions
| @@ -19,125 +19,138 @@ | @@ -19,125 +19,138 @@ | ||
| 19 | part of pdf; | 19 | part of pdf; |
| 20 | 20 | ||
| 21 | class PdfAnnot extends PdfObject { | 21 | class PdfAnnot extends PdfObject { |
| 22 | - PdfAnnot._create(PdfPage pdfPage, | ||
| 23 | - {String type, | ||
| 24 | - this.content, | ||
| 25 | - this.srcRect, | ||
| 26 | - @required this.subtype, | ||
| 27 | - this.dest, | ||
| 28 | - this.destRect, | ||
| 29 | - this.border, | ||
| 30 | - this.url, | ||
| 31 | - this.name}) | ||
| 32 | - : assert(subtype != null), | ||
| 33 | - super(pdfPage.pdfDocument, type ?? '/Annot') { | 22 | + PdfAnnot(this.pdfPage, this.annot) |
| 23 | + : assert(annot != null), | ||
| 24 | + super(pdfPage.pdfDocument, '/Annot') { | ||
| 34 | pdfPage.annotations.add(this); | 25 | pdfPage.annotations.add(this); |
| 35 | } | 26 | } |
| 36 | 27 | ||
| 37 | - /// Creates a text annotation | ||
| 38 | - /// @param rect coordinates | ||
| 39 | - /// @param s Text for this annotation | 28 | + /// Create a text annotation |
| 29 | + @deprecated | ||
| 40 | factory PdfAnnot.text( | 30 | factory PdfAnnot.text( |
| 41 | PdfPage pdfPage, { | 31 | PdfPage pdfPage, { |
| 42 | @required PdfRect rect, | 32 | @required PdfRect rect, |
| 43 | @required String content, | 33 | @required String content, |
| 44 | PdfBorder border, | 34 | PdfBorder border, |
| 45 | }) => | 35 | }) => |
| 46 | - PdfAnnot._create( | ||
| 47 | - pdfPage, | ||
| 48 | - subtype: '/Text', | ||
| 49 | - srcRect: rect, | ||
| 50 | - content: content, | ||
| 51 | - border: border, | ||
| 52 | - ); | ||
| 53 | - | ||
| 54 | - /// Creates a link annotation | ||
| 55 | - /// @param srcRect coordinates | ||
| 56 | - /// @param dest Destination for this link. The page will fit the display. | ||
| 57 | - /// @param destRect Rectangle describing what part of the page to be displayed | ||
| 58 | - /// (must be in User Coordinates) | ||
| 59 | - factory PdfAnnot.link( | ||
| 60 | - PdfPage pdfPage, { | ||
| 61 | - @required PdfRect srcRect, | ||
| 62 | - @required PdfPage dest, | ||
| 63 | - PdfRect destRect, | ||
| 64 | - PdfBorder border, | ||
| 65 | - }) => | ||
| 66 | - PdfAnnot._create( | ||
| 67 | - pdfPage, | ||
| 68 | - subtype: '/Link', | ||
| 69 | - srcRect: srcRect, | ||
| 70 | - dest: dest, | ||
| 71 | - destRect: destRect, | ||
| 72 | - border: border, | ||
| 73 | - ); | 36 | + PdfAnnot( |
| 37 | + pdfPage, | ||
| 38 | + PdfAnnotText( | ||
| 39 | + rect: rect, | ||
| 40 | + content: content, | ||
| 41 | + border: border, | ||
| 42 | + )); | ||
| 74 | 43 | ||
| 75 | /// Creates an external link annotation | 44 | /// Creates an external link annotation |
| 45 | + @deprecated | ||
| 76 | factory PdfAnnot.urlLink( | 46 | factory PdfAnnot.urlLink( |
| 77 | PdfPage pdfPage, { | 47 | PdfPage pdfPage, { |
| 78 | @required PdfRect rect, | 48 | @required PdfRect rect, |
| 79 | @required String dest, | 49 | @required String dest, |
| 80 | PdfBorder border, | 50 | PdfBorder border, |
| 81 | }) => | 51 | }) => |
| 82 | - PdfAnnot._create( | ||
| 83 | - pdfPage, | ||
| 84 | - subtype: '/Link', | ||
| 85 | - srcRect: rect, | ||
| 86 | - url: dest, | ||
| 87 | - border: border, | ||
| 88 | - ); | 52 | + PdfAnnot( |
| 53 | + pdfPage, | ||
| 54 | + PdfAnnotUrlLink( | ||
| 55 | + rect: rect, | ||
| 56 | + url: dest, | ||
| 57 | + border: border, | ||
| 58 | + )); | ||
| 89 | 59 | ||
| 90 | /// Creates a link annotation to a named destination | 60 | /// Creates a link annotation to a named destination |
| 61 | + @deprecated | ||
| 91 | factory PdfAnnot.namedLink( | 62 | factory PdfAnnot.namedLink( |
| 92 | PdfPage pdfPage, { | 63 | PdfPage pdfPage, { |
| 93 | @required PdfRect rect, | 64 | @required PdfRect rect, |
| 94 | @required String dest, | 65 | @required String dest, |
| 95 | PdfBorder border, | 66 | PdfBorder border, |
| 96 | }) => | 67 | }) => |
| 97 | - PdfAnnot._create( | 68 | + PdfAnnot( |
| 98 | pdfPage, | 69 | pdfPage, |
| 99 | - subtype: '/Link', | ||
| 100 | - srcRect: rect, | ||
| 101 | - name: dest, | ||
| 102 | - border: border, | 70 | + PdfAnnotNamedLink( |
| 71 | + rect: rect, | ||
| 72 | + dest: dest, | ||
| 73 | + border: border, | ||
| 74 | + ), | ||
| 103 | ); | 75 | ); |
| 104 | 76 | ||
| 105 | - /// The subtype of the outline, ie text, note, etc | ||
| 106 | - final String subtype; | 77 | + /// The annotation content |
| 78 | + final PdfAnnotBase annot; | ||
| 107 | 79 | ||
| 108 | - /// The size of the annotation | ||
| 109 | - final PdfRect srcRect; | 80 | + /// The page where the annotation will display |
| 81 | + final PdfPage pdfPage; | ||
| 110 | 82 | ||
| 111 | - /// The text of a text annotation | ||
| 112 | - final String content; | 83 | + /// Output the annotation |
| 84 | + /// | ||
| 85 | + /// @param os OutputStream to send the object to | ||
| 86 | + @override | ||
| 87 | + void _prepare() { | ||
| 88 | + super._prepare(); | ||
| 89 | + annot.build(pdfPage, params); | ||
| 90 | + } | ||
| 91 | +} | ||
| 113 | 92 | ||
| 114 | - /// Link to the Destination page | ||
| 115 | - final PdfObject dest; | 93 | +enum PdfAnnotFlags { |
| 94 | + invisible, | ||
| 95 | + hidden, | ||
| 96 | + print, | ||
| 97 | + noZoom, | ||
| 98 | + noRotate, | ||
| 99 | + noView, | ||
| 100 | + readOnly, | ||
| 101 | + locked, | ||
| 102 | + toggleNoView, | ||
| 103 | + lockedContent | ||
| 104 | +} | ||
| 116 | 105 | ||
| 117 | - /// If destRect is null then this is the region of the destination page shown. | ||
| 118 | - /// Otherwise they are ignored. | ||
| 119 | - final PdfRect destRect; | 106 | +abstract class PdfAnnotBase { |
| 107 | + const PdfAnnotBase({ | ||
| 108 | + @required this.subtype, | ||
| 109 | + @required this.rect, | ||
| 110 | + this.border, | ||
| 111 | + this.content, | ||
| 112 | + this.name, | ||
| 113 | + this.flags, | ||
| 114 | + this.date, | ||
| 115 | + this.color, | ||
| 116 | + }) : assert(subtype != null), | ||
| 117 | + assert(rect != null); | ||
| 118 | + | ||
| 119 | + /// The subtype of the outline, ie text, note, etc | ||
| 120 | + final String subtype; | ||
| 121 | + | ||
| 122 | + final PdfRect rect; | ||
| 120 | 123 | ||
| 121 | /// the border for this annotation | 124 | /// the border for this annotation |
| 122 | final PdfBorder border; | 125 | final PdfBorder border; |
| 123 | 126 | ||
| 124 | - /// The external url for a link | ||
| 125 | - final String url; | 127 | + /// The text of a text annotation |
| 128 | + final String content; | ||
| 126 | 129 | ||
| 127 | /// The internal name for a link | 130 | /// The internal name for a link |
| 128 | final String name; | 131 | final String name; |
| 129 | 132 | ||
| 130 | - /// Output the annotation | ||
| 131 | - /// | ||
| 132 | - /// @param os OutputStream to send the object to | ||
| 133 | - @override | ||
| 134 | - void _prepare() { | ||
| 135 | - super._prepare(); | 133 | + /// Flags specifying various characteristics of the annotation |
| 134 | + final Set<PdfAnnotFlags> flags; | ||
| 136 | 135 | ||
| 136 | + /// Last modification date | ||
| 137 | + final DateTime date; | ||
| 138 | + | ||
| 139 | + /// Color | ||
| 140 | + final PdfColor color; | ||
| 141 | + | ||
| 142 | + int get flagValue => flags | ||
| 143 | + ?.map<int>((PdfAnnotFlags e) => 1 >> e.index) | ||
| 144 | + ?.reduce((int a, int b) => a | b); | ||
| 145 | + | ||
| 146 | + @protected | ||
| 147 | + @mustCallSuper | ||
| 148 | + void build(PdfPage page, Map<String, PdfStream> params) { | ||
| 137 | params['/Subtype'] = PdfStream.string(subtype); | 149 | params['/Subtype'] = PdfStream.string(subtype); |
| 138 | params['/Rect'] = PdfStream() | 150 | params['/Rect'] = PdfStream() |
| 139 | - ..putNumArray( | ||
| 140 | - <double>[srcRect.left, srcRect.bottom, srcRect.right, srcRect.top]); | 151 | + ..putNumArray(<double>[rect.left, rect.bottom, rect.right, rect.top]); |
| 152 | + | ||
| 153 | + params['/P'] = page.ref(); | ||
| 141 | 154 | ||
| 142 | // handle the border | 155 | // handle the border |
| 143 | if (border == null) { | 156 | if (border == null) { |
| @@ -146,39 +159,194 @@ class PdfAnnot extends PdfObject { | @@ -146,39 +159,194 @@ class PdfAnnot extends PdfObject { | ||
| 146 | params['/BS'] = border.ref(); | 159 | params['/BS'] = border.ref(); |
| 147 | } | 160 | } |
| 148 | 161 | ||
| 149 | - // Now the annotation subtypes | ||
| 150 | - if (subtype == '/Text') { | 162 | + if (content != null) { |
| 151 | params['/Contents'] = PdfStream()..putLiteral(content); | 163 | params['/Contents'] = PdfStream()..putLiteral(content); |
| 152 | - } else if (subtype == '/Link') { | ||
| 153 | - if (url != null) { | ||
| 154 | - params['/A'] = PdfStream() | ||
| 155 | - ..putDictionary(<String, PdfStream>{ | ||
| 156 | - '/S': PdfStream()..putString('/URI'), | ||
| 157 | - '/URI': PdfStream()..putText(url), | ||
| 158 | - }); | ||
| 159 | - } else if (name != null) { | ||
| 160 | - params['/A'] = PdfStream() | ||
| 161 | - ..putDictionary(<String, PdfStream>{ | ||
| 162 | - '/S': PdfStream()..putString('/GoTo'), | ||
| 163 | - '/D': PdfStream()..putText(name), | ||
| 164 | - }); | 164 | + } |
| 165 | + | ||
| 166 | + if (name != null) { | ||
| 167 | + params['/NM'] = PdfStream()..putLiteral(name); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + if (flags != null) { | ||
| 171 | + params['/F'] = PdfStream.intNum(flagValue); | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + if (date != null) { | ||
| 175 | + params['/M'] = PdfStream()..putDate(date); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + if (color != null) { | ||
| 179 | + if (color is PdfColorCmyk) { | ||
| 180 | + final PdfColorCmyk k = color; | ||
| 181 | + params['/C'] = PdfStream() | ||
| 182 | + ..putNumList(<double>[k.cyan, k.magenta, k.yellow, k.black]); | ||
| 165 | } else { | 183 | } else { |
| 166 | - final List<PdfStream> dests = <PdfStream>[]; | ||
| 167 | - dests.add(dest.ref()); | ||
| 168 | - if (destRect == null) { | ||
| 169 | - dests.add(PdfStream.string('/Fit')); | ||
| 170 | - } else { | ||
| 171 | - dests.add(PdfStream.string('/FitR ')); | ||
| 172 | - dests.add(PdfStream() | ||
| 173 | - ..putNumList(<double>[ | ||
| 174 | - destRect.left, | ||
| 175 | - destRect.bottom, | ||
| 176 | - destRect.right, | ||
| 177 | - destRect.top | ||
| 178 | - ])); | ||
| 179 | - } | ||
| 180 | - params['/Dest'] = PdfStream.array(dests); | 184 | + params['/C'] = PdfStream() |
| 185 | + ..putNumList(<double>[color.red, color.green, color.blue]); | ||
| 181 | } | 186 | } |
| 182 | } | 187 | } |
| 183 | } | 188 | } |
| 184 | } | 189 | } |
| 190 | + | ||
| 191 | +class PdfAnnotText extends PdfAnnotBase { | ||
| 192 | + /// Create a text annotation | ||
| 193 | + const PdfAnnotText({ | ||
| 194 | + @required PdfRect rect, | ||
| 195 | + @required String content, | ||
| 196 | + PdfBorder border, | ||
| 197 | + String name, | ||
| 198 | + Set<PdfAnnotFlags> flags, | ||
| 199 | + DateTime date, | ||
| 200 | + PdfColor color, | ||
| 201 | + }) : super( | ||
| 202 | + subtype: '/Text', | ||
| 203 | + rect: rect, | ||
| 204 | + border: border, | ||
| 205 | + content: content, | ||
| 206 | + name: name, | ||
| 207 | + flags: flags, | ||
| 208 | + date: date, | ||
| 209 | + color: color, | ||
| 210 | + ); | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +class PdfAnnotNamedLink extends PdfAnnotBase { | ||
| 214 | + /// Create a named link annotation | ||
| 215 | + const PdfAnnotNamedLink({ | ||
| 216 | + @required PdfRect rect, | ||
| 217 | + @required this.dest, | ||
| 218 | + PdfBorder border, | ||
| 219 | + Set<PdfAnnotFlags> flags, | ||
| 220 | + DateTime date, | ||
| 221 | + PdfColor color, | ||
| 222 | + }) : super( | ||
| 223 | + subtype: '/Link', | ||
| 224 | + rect: rect, | ||
| 225 | + border: border, | ||
| 226 | + flags: flags, | ||
| 227 | + date: date, | ||
| 228 | + color: color, | ||
| 229 | + ); | ||
| 230 | + | ||
| 231 | + final String dest; | ||
| 232 | + | ||
| 233 | + @override | ||
| 234 | + void build(PdfPage page, Map<String, PdfStream> params) { | ||
| 235 | + super.build(page, params); | ||
| 236 | + params['/A'] = PdfStream() | ||
| 237 | + ..putDictionary( | ||
| 238 | + <String, PdfStream>{ | ||
| 239 | + '/S': PdfStream()..putString('/GoTo'), | ||
| 240 | + '/D': PdfStream()..putText(dest), | ||
| 241 | + }, | ||
| 242 | + ); | ||
| 243 | + } | ||
| 244 | +} | ||
| 245 | + | ||
| 246 | +class PdfAnnotUrlLink extends PdfAnnotBase { | ||
| 247 | + /// Create an url link annotation | ||
| 248 | + const PdfAnnotUrlLink({ | ||
| 249 | + @required PdfRect rect, | ||
| 250 | + @required this.url, | ||
| 251 | + PdfBorder border, | ||
| 252 | + Set<PdfAnnotFlags> flags, | ||
| 253 | + DateTime date, | ||
| 254 | + PdfColor color, | ||
| 255 | + }) : super( | ||
| 256 | + subtype: '/Link', | ||
| 257 | + rect: rect, | ||
| 258 | + border: border, | ||
| 259 | + flags: flags, | ||
| 260 | + date: date, | ||
| 261 | + color: color, | ||
| 262 | + ); | ||
| 263 | + | ||
| 264 | + final String url; | ||
| 265 | + | ||
| 266 | + @override | ||
| 267 | + void build(PdfPage page, Map<String, PdfStream> params) { | ||
| 268 | + super.build(page, params); | ||
| 269 | + params['/A'] = PdfStream() | ||
| 270 | + ..putDictionary( | ||
| 271 | + <String, PdfStream>{ | ||
| 272 | + '/S': PdfStream()..putString('/URI'), | ||
| 273 | + '/URI': PdfStream()..putText(url), | ||
| 274 | + }, | ||
| 275 | + ); | ||
| 276 | + } | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +enum PdfAnnotHighlighting { none, invert, outline, push, toggle } | ||
| 280 | + | ||
| 281 | +abstract class PdfAnnotWidget extends PdfAnnotBase { | ||
| 282 | + /// Create an url link annotation | ||
| 283 | + const PdfAnnotWidget( | ||
| 284 | + PdfRect rect, | ||
| 285 | + this.fieldType, { | ||
| 286 | + this.fieldName, | ||
| 287 | + PdfBorder border, | ||
| 288 | + Set<PdfAnnotFlags> flags, | ||
| 289 | + DateTime date, | ||
| 290 | + PdfColor color, | ||
| 291 | + this.highlighting, | ||
| 292 | + this.value, | ||
| 293 | + }) : super( | ||
| 294 | + subtype: '/Widget', | ||
| 295 | + rect: rect, | ||
| 296 | + border: border, | ||
| 297 | + flags: flags, | ||
| 298 | + date: date, | ||
| 299 | + color: color, | ||
| 300 | + ); | ||
| 301 | + | ||
| 302 | + final String fieldType; | ||
| 303 | + | ||
| 304 | + final String fieldName; | ||
| 305 | + | ||
| 306 | + final PdfAnnotHighlighting highlighting; | ||
| 307 | + | ||
| 308 | + final PdfStream value; | ||
| 309 | + | ||
| 310 | + @override | ||
| 311 | + void build(PdfPage page, Map<String, PdfStream> params) { | ||
| 312 | + super.build(page, params); | ||
| 313 | + | ||
| 314 | + params['/FT'] = PdfStream.string(fieldType); | ||
| 315 | + | ||
| 316 | + if (fieldName != null) { | ||
| 317 | + params['/T'] = PdfStream()..putLiteral(fieldName); | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + if (value != null) { | ||
| 321 | + params['/V'] = value; | ||
| 322 | + } | ||
| 323 | + } | ||
| 324 | +} | ||
| 325 | + | ||
| 326 | +class PdfAnnotSign extends PdfAnnotWidget { | ||
| 327 | + const PdfAnnotSign( | ||
| 328 | + PdfRect rect, { | ||
| 329 | + String fieldName, | ||
| 330 | + PdfBorder border, | ||
| 331 | + Set<PdfAnnotFlags> flags, | ||
| 332 | + DateTime date, | ||
| 333 | + PdfColor color, | ||
| 334 | + PdfAnnotHighlighting highlighting, | ||
| 335 | + }) : super( | ||
| 336 | + rect, | ||
| 337 | + '/Sig', | ||
| 338 | + fieldName: fieldName, | ||
| 339 | + border: border, | ||
| 340 | + flags: flags, | ||
| 341 | + date: date, | ||
| 342 | + color: color, | ||
| 343 | + highlighting: highlighting, | ||
| 344 | + ); | ||
| 345 | + | ||
| 346 | + @override | ||
| 347 | + void build(PdfPage page, Map<String, PdfStream> params) { | ||
| 348 | + super.build(page, params); | ||
| 349 | + assert(page.pdfDocument.sign != null); | ||
| 350 | + params['/V'] = page.pdfDocument.sign.ref(); | ||
| 351 | + } | ||
| 352 | +} |
| @@ -14,6 +14,8 @@ | @@ -14,6 +14,8 @@ | ||
| 14 | * limitations under the License. | 14 | * limitations under the License. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | +// ignore_for_file: omit_local_variable_types | ||
| 18 | + | ||
| 17 | part of pdf; | 19 | part of pdf; |
| 18 | 20 | ||
| 19 | class PdfCatalog extends PdfObject { | 21 | class PdfCatalog extends PdfObject { |
| @@ -67,8 +69,25 @@ class PdfCatalog extends PdfObject { | @@ -67,8 +69,25 @@ class PdfCatalog extends PdfObject { | ||
| 67 | PdfStream.string(PdfDocument._PdfPageModes[pageMode.index]); | 69 | PdfStream.string(PdfDocument._PdfPageModes[pageMode.index]); |
| 68 | 70 | ||
| 69 | if (pdfDocument.sign != null) { | 71 | if (pdfDocument.sign != null) { |
| 70 | - params['/Perms'] = PdfStream.dictionary( | ||
| 71 | - <String, PdfStream>{'/DocMDP': pdfDocument.sign.ref()}); | 72 | + params['/Perms'] = PdfStream.dictionary(<String, PdfStream>{ |
| 73 | + '/DocMDP': pdfDocument.sign.ref(), | ||
| 74 | + }); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + final List<PdfAnnot> widgets = <PdfAnnot>[]; | ||
| 78 | + for (PdfPage page in pdfDocument.pdfPageList.pages) { | ||
| 79 | + for (PdfAnnot annot in page.annotations) { | ||
| 80 | + if (annot.annot.subtype == '/Widget') { | ||
| 81 | + widgets.add(annot); | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + if (widgets.isNotEmpty) { | ||
| 87 | + params['/AcroForm'] = PdfStream.dictionary(<String, PdfStream>{ | ||
| 88 | + '/SigFlags': PdfStream.intNum(pdfDocument.sign?.flagsValue ?? 0), | ||
| 89 | + '/Fields': PdfStream()..putObjectArray(widgets), | ||
| 90 | + }); | ||
| 72 | } | 91 | } |
| 73 | } | 92 | } |
| 74 | } | 93 | } |
| @@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | // ignore_for_file: omit_local_variable_types | 17 | // ignore_for_file: omit_local_variable_types |
| 18 | +// ignore_for_file: avoid_unused_constructor_parameters | ||
| 18 | 19 | ||
| 19 | part of pdf; | 20 | part of pdf; |
| 20 | 21 | ||
| @@ -33,13 +34,7 @@ class PDFAnnot extends PdfAnnot { | @@ -33,13 +34,7 @@ class PDFAnnot extends PdfAnnot { | ||
| 33 | double fb, | 34 | double fb, |
| 34 | double fr, | 35 | double fr, |
| 35 | double ft}) | 36 | double ft}) |
| 36 | - : super._create(pdfPage, | ||
| 37 | - type: type, | ||
| 38 | - content: s, | ||
| 39 | - srcRect: PdfRect.fromLTRB(l, t, r, b), | ||
| 40 | - subtype: subtype, | ||
| 41 | - dest: dest, | ||
| 42 | - destRect: PdfRect.fromLTRB(fl, ft, fr, fb)); | 37 | + : super(pdfPage, PdfAnnotText(rect: PdfRect(l, b, r, t), content: s)); |
| 43 | 38 | ||
| 44 | factory PDFAnnot.annotation( | 39 | factory PDFAnnot.annotation( |
| 45 | PdfPage pdfPage, String s, double l, double b, double r, double t) => | 40 | PdfPage pdfPage, String s, double l, double b, double r, double t) => |
| @@ -342,12 +337,11 @@ class PDFPage extends PdfPage { | @@ -342,12 +337,11 @@ class PDFPage extends PdfPage { | ||
| 342 | double vh = PDFAnnot.FULL_PAGE]) { | 337 | double vh = PDFAnnot.FULL_PAGE]) { |
| 343 | final PdfPoint xy1 = cxy(x, y + h); | 338 | final PdfPoint xy1 = cxy(x, y + h); |
| 344 | final PdfPoint xy2 = cxy(x + w, y); | 339 | final PdfPoint xy2 = cxy(x + w, y); |
| 345 | - final PdfPoint xy3 = cxy(vx, vy + vh); | ||
| 346 | - final PdfPoint xy4 = cxy(vx + vw, vy); | ||
| 347 | - final PdfAnnot ob = PdfAnnot.link(this, | ||
| 348 | - srcRect: PdfRect.fromLTRB(xy1.x, xy1.y, xy2.x, xy2.y), | ||
| 349 | - dest: dest, | ||
| 350 | - destRect: PdfRect.fromLTRB(xy3.x, xy3.y, xy4.x, xy4.y)); | 340 | + final PdfAnnot ob = PdfAnnot.urlLink( |
| 341 | + this, | ||
| 342 | + rect: PdfRect.fromLTRB(xy1.x, xy1.y, xy2.x, xy2.y), | ||
| 343 | + dest: 'https://github.com/DavBfr/dart_pdf', | ||
| 344 | + ); | ||
| 351 | return ob; | 345 | return ob; |
| 352 | } | 346 | } |
| 353 | 347 |
| @@ -107,7 +107,7 @@ class PdfPage extends PdfObject { | @@ -107,7 +107,7 @@ class PdfPage extends PdfObject { | ||
| 107 | // the /Contents pages object | 107 | // the /Contents pages object |
| 108 | if (contents.isNotEmpty) { | 108 | if (contents.isNotEmpty) { |
| 109 | if (contents.length == 1) { | 109 | if (contents.length == 1) { |
| 110 | - params['/Contents'] = contents[0].ref(); | 110 | + params['/Contents'] = contents.first.ref(); |
| 111 | } else { | 111 | } else { |
| 112 | params['/Contents'] = PdfStream()..putObjectArray(contents); | 112 | params['/Contents'] = PdfStream()..putObjectArray(contents); |
| 113 | } | 113 | } |
| @@ -18,29 +18,33 @@ | @@ -18,29 +18,33 @@ | ||
| 18 | 18 | ||
| 19 | part of pdf; | 19 | part of pdf; |
| 20 | 20 | ||
| 21 | -@immutable | ||
| 22 | -class PdfSignatureRange { | ||
| 23 | - const PdfSignatureRange(this.start, this.end); | 21 | +enum PdfSigFlags { signaturesExist, appendOnly } |
| 24 | 22 | ||
| 25 | - final int start; | ||
| 26 | - final int end; | ||
| 27 | -} | 23 | +class PdfSignature extends PdfObject { |
| 24 | + PdfSignature( | ||
| 25 | + PdfDocument pdfDocument, { | ||
| 26 | + @required this.crypto, | ||
| 27 | + Set<PdfSigFlags> flags, | ||
| 28 | + }) : assert(crypto != null), | ||
| 29 | + flags = flags ?? const <PdfSigFlags>{PdfSigFlags.signaturesExist}, | ||
| 30 | + super(pdfDocument, '/Sig'); | ||
| 28 | 31 | ||
| 29 | -abstract class PdfSignature extends PdfObject { | ||
| 30 | - PdfSignature(PdfDocument pdfDocument) : super(pdfDocument, '/Sig'); | 32 | + final Set<PdfSigFlags> flags; |
| 31 | 33 | ||
| 32 | - int _offsetStart; | ||
| 33 | - int _offsetEnd; | 34 | + final PdfSignatureBase crypto; |
| 34 | 35 | ||
| 35 | - void preSign(); | 36 | + int get flagsValue => flags |
| 37 | + .map<int>((PdfSigFlags e) => 1 >> e.index) | ||
| 38 | + .reduce((int a, int b) => a | b); | ||
| 36 | 39 | ||
| 37 | - void sign(PdfStream os, List<PdfSignatureRange> ranges); | 40 | + int _offsetStart; |
| 41 | + int _offsetEnd; | ||
| 38 | 42 | ||
| 39 | @override | 43 | @override |
| 40 | void _write(PdfStream os) { | 44 | void _write(PdfStream os) { |
| 41 | - preSign(); | 45 | + crypto.preSign(params); |
| 42 | 46 | ||
| 43 | - _offsetStart = os.offset; | 47 | + _offsetStart = os.offset + '$objser $objgen obj\n'.length; |
| 44 | super._write(os); | 48 | super._write(os); |
| 45 | _offsetEnd = os.offset; | 49 | _offsetEnd = os.offset; |
| 46 | } | 50 | } |
| @@ -49,16 +53,13 @@ abstract class PdfSignature extends PdfObject { | @@ -49,16 +53,13 @@ abstract class PdfSignature extends PdfObject { | ||
| 49 | assert(_offsetStart != null && _offsetEnd != null, | 53 | assert(_offsetStart != null && _offsetEnd != null, |
| 50 | 'Must reserve the object space before signing the document'); | 54 | 'Must reserve the object space before signing the document'); |
| 51 | 55 | ||
| 52 | - final List<PdfSignatureRange> ranges = <PdfSignatureRange>[ | ||
| 53 | - PdfSignatureRange(0, _offsetStart), | ||
| 54 | - PdfSignatureRange(_offsetEnd, os.offset), | ||
| 55 | - ]; | 56 | + crypto.sign(os, params, _offsetStart, _offsetEnd); |
| 57 | + } | ||
| 58 | +} | ||
| 56 | 59 | ||
| 57 | - sign(os, ranges); | ||
| 58 | - final PdfStream signature = PdfStream(); | ||
| 59 | - super._write(signature); | 60 | +abstract class PdfSignatureBase { |
| 61 | + void preSign(Map<String, PdfStream> params); | ||
| 60 | 62 | ||
| 61 | - assert(signature.offset == _offsetEnd - _offsetStart); | ||
| 62 | - os.output().replaceRange(_offsetStart, _offsetEnd, signature.output()); | ||
| 63 | - } | 63 | + void sign(PdfStream os, Map<String, PdfStream> params, int offsetStart, |
| 64 | + int offsetEnd); | ||
| 64 | } | 65 | } |
| @@ -39,7 +39,7 @@ class Anchor extends SingleChildWidget { | @@ -39,7 +39,7 @@ class Anchor extends SingleChildWidget { | ||
| 39 | if (description != null) { | 39 | if (description != null) { |
| 40 | final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0)); | 40 | final Vector3 rb = mat.transform3(Vector3(box.right, box.top, 0)); |
| 41 | final PdfRect ibox = PdfRect.fromLTRB(lt.x, lt.y, rb.x, rb.y); | 41 | final PdfRect ibox = PdfRect.fromLTRB(lt.x, lt.y, rb.x, rb.y); |
| 42 | - PdfAnnot.text(context.page, content: description, rect: ibox); | 42 | + PdfAnnot(context.page, PdfAnnotText(rect: ibox, content: description)); |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
| 45 | } | 45 | } |
| @@ -62,10 +62,12 @@ class AnnotationLink extends AnnotationBuilder { | @@ -62,10 +62,12 @@ class AnnotationLink extends AnnotationBuilder { | ||
| 62 | 62 | ||
| 63 | @override | 63 | @override |
| 64 | void build(Context context, PdfRect box) { | 64 | void build(Context context, PdfRect box) { |
| 65 | - PdfAnnot.namedLink( | 65 | + PdfAnnot( |
| 66 | context.page, | 66 | context.page, |
| 67 | - rect: localToGlobal(context, box), | ||
| 68 | - dest: destination, | 67 | + PdfAnnotNamedLink( |
| 68 | + rect: localToGlobal(context, box), | ||
| 69 | + dest: destination, | ||
| 70 | + ), | ||
| 69 | ); | 71 | ); |
| 70 | } | 72 | } |
| 71 | } | 73 | } |
| @@ -77,10 +79,63 @@ class AnnotationUrl extends AnnotationBuilder { | @@ -77,10 +79,63 @@ class AnnotationUrl extends AnnotationBuilder { | ||
| 77 | 79 | ||
| 78 | @override | 80 | @override |
| 79 | void build(Context context, PdfRect box) { | 81 | void build(Context context, PdfRect box) { |
| 80 | - PdfAnnot.urlLink( | 82 | + PdfAnnot( |
| 81 | context.page, | 83 | context.page, |
| 82 | - rect: localToGlobal(context, box), | ||
| 83 | - dest: destination, | 84 | + PdfAnnotUrlLink( |
| 85 | + rect: localToGlobal(context, box), | ||
| 86 | + url: destination, | ||
| 87 | + ), | ||
| 88 | + ); | ||
| 89 | + } | ||
| 90 | +} | ||
| 91 | + | ||
| 92 | +class AnnotationSignature extends AnnotationBuilder { | ||
| 93 | + AnnotationSignature( | ||
| 94 | + this.crypto, { | ||
| 95 | + this.name, | ||
| 96 | + this.signFlags, | ||
| 97 | + this.border, | ||
| 98 | + this.flags, | ||
| 99 | + this.date, | ||
| 100 | + this.color, | ||
| 101 | + this.highlighting, | ||
| 102 | + }) : assert(crypto != null); | ||
| 103 | + | ||
| 104 | + final Set<PdfSigFlags> signFlags; | ||
| 105 | + | ||
| 106 | + final PdfSignatureBase crypto; | ||
| 107 | + | ||
| 108 | + final String name; | ||
| 109 | + | ||
| 110 | + final PdfBorder border; | ||
| 111 | + | ||
| 112 | + final Set<PdfAnnotFlags> flags; | ||
| 113 | + | ||
| 114 | + final DateTime date; | ||
| 115 | + | ||
| 116 | + final PdfColor color; | ||
| 117 | + | ||
| 118 | + final PdfAnnotHighlighting highlighting; | ||
| 119 | + | ||
| 120 | + @override | ||
| 121 | + void build(Context context, PdfRect box) { | ||
| 122 | + context.document.sign ??= PdfSignature( | ||
| 123 | + context.document, | ||
| 124 | + crypto: crypto, | ||
| 125 | + flags: signFlags, | ||
| 126 | + ); | ||
| 127 | + | ||
| 128 | + PdfAnnot( | ||
| 129 | + context.page, | ||
| 130 | + PdfAnnotSign( | ||
| 131 | + localToGlobal(context, box), | ||
| 132 | + fieldName: name, | ||
| 133 | + border: border, | ||
| 134 | + flags: flags, | ||
| 135 | + date: date, | ||
| 136 | + color: color, | ||
| 137 | + highlighting: highlighting, | ||
| 138 | + ), | ||
| 84 | ); | 139 | ); |
| 85 | } | 140 | } |
| 86 | } | 141 | } |
| @@ -117,3 +172,30 @@ class UrlLink extends Annotation { | @@ -117,3 +172,30 @@ class UrlLink extends Annotation { | ||
| 117 | : assert(child != null), | 172 | : assert(child != null), |
| 118 | super(child: child, builder: AnnotationUrl(destination)); | 173 | super(child: child, builder: AnnotationUrl(destination)); |
| 119 | } | 174 | } |
| 175 | + | ||
| 176 | +class Signature extends Annotation { | ||
| 177 | + Signature({ | ||
| 178 | + @required Widget child, | ||
| 179 | + @required PdfSignatureBase crypto, | ||
| 180 | + @required String name, | ||
| 181 | + Set<PdfSigFlags> signFlags, | ||
| 182 | + PdfBorder border, | ||
| 183 | + Set<PdfAnnotFlags> flags, | ||
| 184 | + DateTime date, | ||
| 185 | + PdfColor color, | ||
| 186 | + PdfAnnotHighlighting highlighting, | ||
| 187 | + }) : assert(child != null), | ||
| 188 | + assert(crypto != null), | ||
| 189 | + super( | ||
| 190 | + child: child, | ||
| 191 | + builder: AnnotationSignature( | ||
| 192 | + crypto, | ||
| 193 | + signFlags: signFlags, | ||
| 194 | + name: name, | ||
| 195 | + border: border, | ||
| 196 | + flags: flags, | ||
| 197 | + date: date, | ||
| 198 | + color: color, | ||
| 199 | + highlighting: highlighting, | ||
| 200 | + )); | ||
| 201 | +} |
| @@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl | @@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl | ||
| 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf | 4 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf |
| 5 | repository: https://github.com/DavBfr/dart_pdf | 5 | repository: https://github.com/DavBfr/dart_pdf |
| 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues | 6 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues |
| 7 | -version: 1.5.0 | 7 | +version: 1.6.0 |
| 8 | 8 | ||
| 9 | environment: | 9 | environment: |
| 10 | sdk: ">=2.3.0 <3.0.0" | 10 | sdk: ">=2.3.0 <3.0.0" |
| @@ -29,18 +29,35 @@ void main() { | @@ -29,18 +29,35 @@ void main() { | ||
| 29 | final PdfPage page1 = | 29 | final PdfPage page1 = |
| 30 | PdfPage(pdf, pageFormat: const PdfPageFormat(500, 300)); | 30 | PdfPage(pdf, pageFormat: const PdfPageFormat(500, 300)); |
| 31 | 31 | ||
| 32 | + pdf.pdfNames.addDest('target', page1, posY: 100); | ||
| 33 | + | ||
| 32 | final PdfGraphics g = page.getGraphics(); | 34 | final PdfGraphics g = page.getGraphics(); |
| 33 | 35 | ||
| 34 | - PdfAnnot.text(page, | ||
| 35 | - content: 'Hello', rect: const PdfRect(100, 100, 50, 50)); | 36 | + PdfAnnot( |
| 37 | + page, | ||
| 38 | + const PdfAnnotText( | ||
| 39 | + rect: PdfRect(100, 100, 50, 50), | ||
| 40 | + content: 'Hello', | ||
| 41 | + ), | ||
| 42 | + ); | ||
| 36 | 43 | ||
| 37 | - PdfAnnot.link(page, dest: page1, srcRect: const PdfRect(100, 150, 50, 50)); | 44 | + PdfAnnot( |
| 45 | + page, | ||
| 46 | + const PdfAnnotNamedLink( | ||
| 47 | + dest: 'target', | ||
| 48 | + rect: PdfRect(100, 150, 50, 50), | ||
| 49 | + ), | ||
| 50 | + ); | ||
| 38 | g.drawRect(100, 150, 50, 50); | 51 | g.drawRect(100, 150, 50, 50); |
| 39 | g.strokePath(); | 52 | g.strokePath(); |
| 40 | 53 | ||
| 41 | - PdfAnnot.urlLink(page, | ||
| 42 | - rect: const PdfRect(100, 250, 50, 50), | ||
| 43 | - dest: 'https://github.com/DavBfr/dart_pdf/'); | 54 | + PdfAnnot( |
| 55 | + page, | ||
| 56 | + const PdfAnnotUrlLink( | ||
| 57 | + rect: PdfRect(100, 250, 50, 50), | ||
| 58 | + url: 'https://github.com/DavBfr/dart_pdf/', | ||
| 59 | + ), | ||
| 60 | + ); | ||
| 44 | g.drawRect(100, 250, 50, 50); | 61 | g.drawRect(100, 250, 50, 50); |
| 45 | g.strokePath(); | 62 | g.strokePath(); |
| 46 | 63 |
-
Please register or login to post a comment