David PHAM-VAN

Add Opacity Widget

@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 - Fix HSV and HSL Color constructors 9 - Fix HSV and HSL Color constructors
10 - Add PageTheme.copyWith 10 - Add PageTheme.copyWith
11 - Add more font drawing options 11 - Add more font drawing options
  12 +- Add Opacity Widget
12 13
13 ## 1.4.1 14 ## 1.4.1
14 15
@@ -40,22 +40,23 @@ part 'src/colors.dart'; @@ -40,22 +40,23 @@ part 'src/colors.dart';
40 part 'src/compatibility.dart'; 40 part 'src/compatibility.dart';
41 part 'src/document.dart'; 41 part 'src/document.dart';
42 part 'src/encryption.dart'; 42 part 'src/encryption.dart';
43 -part 'src/font_descriptor.dart';  
44 part 'src/exif.dart'; 43 part 'src/exif.dart';
45 -part 'src/font_metrics.dart';  
46 part 'src/font.dart'; 44 part 'src/font.dart';
  45 +part 'src/font_descriptor.dart';
  46 +part 'src/font_metrics.dart';
47 part 'src/formxobject.dart'; 47 part 'src/formxobject.dart';
  48 +part 'src/graphic_state.dart';
48 part 'src/graphics.dart'; 49 part 'src/graphics.dart';
49 part 'src/image.dart'; 50 part 'src/image.dart';
50 part 'src/info.dart'; 51 part 'src/info.dart';
51 part 'src/names.dart'; 52 part 'src/names.dart';
52 -part 'src/object_stream.dart';  
53 part 'src/object.dart'; 53 part 'src/object.dart';
  54 +part 'src/object_stream.dart';
54 part 'src/outline.dart'; 55 part 'src/outline.dart';
55 part 'src/output.dart'; 56 part 'src/output.dart';
  57 +part 'src/page.dart';
56 part 'src/page_format.dart'; 58 part 'src/page_format.dart';
57 part 'src/page_list.dart'; 59 part 'src/page_list.dart';
58 -part 'src/page.dart';  
59 part 'src/point.dart'; 60 part 'src/point.dart';
60 part 'src/polygon.dart'; 61 part 'src/polygon.dart';
61 part 'src/rect.dart'; 62 part 'src/rect.dart';
@@ -98,6 +98,9 @@ class PdfDocument { @@ -98,6 +98,9 @@ class PdfDocument {
98 /// Object used to sign the document 98 /// Object used to sign the document
99 PdfSignature sign; 99 PdfSignature sign;
100 100
  101 + /// Graphics state, representing only opacity.
  102 + PdfGraphicStates _graphicStates;
  103 +
101 /// The PDF specification version 104 /// The PDF specification version
102 final String version = '1.7'; 105 final String version = '1.7';
103 106
@@ -149,6 +152,14 @@ class PdfDocument { @@ -149,6 +152,14 @@ class PdfDocument {
149 return _outline; 152 return _outline;
150 } 153 }
151 154
  155 + /// Graphic states for opacity and transfer modes
  156 + PdfGraphicStates get graphicStates {
  157 + _graphicStates ??= PdfGraphicStates(this);
  158 + return _graphicStates;
  159 + }
  160 +
  161 + bool get hasGraphicStates => _graphicStates != null;
  162 +
152 /// This writes the document to an OutputStream. 163 /// This writes the document to an OutputStream.
153 /// 164 ///
154 /// Note: You can call this as many times as you wish, as long as 165 /// Note: You can call this as many times as you wish, as long as
  1 +/*
  2 + * Copyright (C) 2017, David PHAM-VAN <dev.nfet.net@gmail.com>
  3 + *
  4 + * This library is free software; you can redistribute it and/or
  5 + * modify it under the terms of the GNU Lesser General
  6 + * License as published by the Free Software Foundation; either
  7 + * version 2.1 of the License, or (at your option) any later version.
  8 + *
  9 + * This library is distributed in the hope that it will be useful,
  10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12 + * Lesser General License for more details.
  13 + *
  14 + * You should have received a copy of the GNU Lesser General
  15 + * License along with this library; if not, write to the Free Software
  16 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17 + */
  18 +
  19 +// ignore_for_file: omit_local_variable_types
  20 +
  21 +part of pdf;
  22 +
  23 +@immutable
  24 +class PdfGraphicState {
  25 + const PdfGraphicState({this.opacity});
  26 +
  27 + final double opacity;
  28 +
  29 + @protected
  30 + PdfStream _output() {
  31 + final Map<String, PdfStream> params = <String, PdfStream>{};
  32 +
  33 + if (opacity != null) {
  34 + params['/CA'] = PdfStream.num(opacity);
  35 + params['/ca'] = PdfStream.num(opacity);
  36 + }
  37 +
  38 + return PdfStream.dictionary(params);
  39 + }
  40 +
  41 + @override
  42 + bool operator ==(dynamic other) {
  43 + if (!other is PdfGraphicState) {
  44 + return false;
  45 + }
  46 + return other.opacity == opacity;
  47 + }
  48 +
  49 + @override
  50 + int get hashCode => opacity.hashCode;
  51 +}
  52 +
  53 +class PdfGraphicStates extends PdfObject {
  54 + PdfGraphicStates(PdfDocument pdfDocument) : super(pdfDocument);
  55 +
  56 + final List<PdfGraphicState> _states = <PdfGraphicState>[];
  57 +
  58 + static const String _prefix = '/a';
  59 +
  60 + String stateName(PdfGraphicState state) {
  61 + int index = _states.indexOf(state);
  62 + if (index < 0) {
  63 + index = _states.length;
  64 + _states.add(state);
  65 + }
  66 + return '$_prefix$index';
  67 + }
  68 +
  69 + @override
  70 + void _prepare() {
  71 + super._prepare();
  72 +
  73 + for (int index = 0; index < _states.length; index++) {
  74 + params['$_prefix$index'] = _states[index]._output();
  75 + }
  76 + }
  77 +}
@@ -320,6 +320,12 @@ class PdfGraphics { @@ -320,6 +320,12 @@ class PdfGraphics {
320 } 320 }
321 } 321 }
322 322
  323 + /// Set the graphic state for drawing
  324 + void setGraphicState(PdfGraphicState state) {
  325 + final String name = page.pdfDocument.graphicStates.stateName(state);
  326 + buf.putString('$name gs\n');
  327 + }
  328 +
323 /// Set the transformation Matrix 329 /// Set the transformation Matrix
324 void setTransform(Matrix4 t) { 330 void setTransform(Matrix4 t) {
325 final Float64List s = t.storage; 331 final Float64List s = t.storage;
@@ -41,6 +41,18 @@ class PdfPage extends PdfObject { @@ -41,6 +41,18 @@ class PdfPage extends PdfObject {
41 /// -1 indicates no thumbnail. 41 /// -1 indicates no thumbnail.
42 PdfObject thumbnail; 42 PdfObject thumbnail;
43 43
  44 + /// Isolated transparency: If this flag is true, objects within the group
  45 + /// shall be composited against a fully transparent initial backdrop;
  46 + /// if false, they shall be composited against the group’s backdrop
  47 + bool isolatedTransparency = false;
  48 +
  49 + /// Whether the transparency group is a knockout group.
  50 + /// If this flag is false, later objects within the group shall be composited
  51 + /// with earlier ones with which they overlap; if true, they shall be
  52 + /// composited with the group’s initial backdrop and shall overwrite any
  53 + /// earlier overlapping objects.
  54 + bool knockoutTransparency = false;
  55 +
44 /// This holds any Annotations contained within this page. 56 /// This holds any Annotations contained within this page.
45 List<PdfAnnot> annotations = <PdfAnnot>[]; 57 List<PdfAnnot> annotations = <PdfAnnot>[];
46 58
@@ -115,6 +127,20 @@ class PdfPage extends PdfObject { @@ -115,6 +127,20 @@ class PdfPage extends PdfObject {
115 resources['/XObject'] = PdfStream()..putObjectDictionary(xObjects); 127 resources['/XObject'] = PdfStream()..putObjectDictionary(xObjects);
116 } 128 }
117 129
  130 + if (pdfDocument.hasGraphicStates) {
  131 + // Declare Transparency Group settings
  132 + params['/Group'] = PdfStream()
  133 + ..putDictionary(<String, PdfStream>{
  134 + '/Type': PdfStream.string('/Group'),
  135 + '/S': PdfStream.string('/Transparency'),
  136 + '/CS': PdfStream.string('/DeviceRGB'),
  137 + '/I': PdfStream()..putBool(isolatedTransparency),
  138 + '/K': PdfStream()..putBool(knockoutTransparency),
  139 + });
  140 +
  141 + resources['/ExtGState'] = pdfDocument.graphicStates.ref();
  142 + }
  143 +
118 params['/Resources'] = PdfStream.dictionary(resources); 144 params['/Resources'] = PdfStream.dictionary(resources);
119 145
120 // The thumbnail 146 // The thumbnail
@@ -740,3 +740,29 @@ class FullPage extends SingleChildWidget { @@ -740,3 +740,29 @@ class FullPage extends SingleChildWidget {
740 context.canvas.restoreContext(); 740 context.canvas.restoreContext();
741 } 741 }
742 } 742 }
  743 +
  744 +class Opacity extends SingleChildWidget {
  745 + Opacity({
  746 + @required this.opacity,
  747 + Widget child,
  748 + }) : assert(opacity != null),
  749 + super(child: child);
  750 +
  751 + final double opacity;
  752 +
  753 + @override
  754 + void paint(Context context) {
  755 + super.paint(context);
  756 +
  757 + if (child != null) {
  758 + final Matrix4 mat = Matrix4.identity();
  759 + mat.translate(box.x, box.y);
  760 + context.canvas
  761 + ..saveContext()
  762 + ..setTransform(mat)
  763 + ..setGraphicState(PdfGraphicState(opacity: opacity));
  764 + child.paint(context);
  765 + context.canvas.restoreContext();
  766 + }
  767 + }
  768 +}