David PHAM-VAN

Improve image buffer management

@@ -11,6 +11,7 @@ @@ -11,6 +11,7 @@
11 - Uniformize examples 11 - Uniformize examples
12 - Fix context painting empty Table 12 - Fix context painting empty Table
13 - Fix Text decoration placements 13 - Fix Text decoration placements
  14 +- Improve image buffer management
14 15
15 ## 1.5.0 16 ## 1.5.0
16 17
@@ -33,11 +33,6 @@ enum PdfImageOrientation { @@ -33,11 +33,6 @@ enum PdfImageOrientation {
33 33
34 class PdfImage extends PdfXObject { 34 class PdfImage extends PdfXObject {
35 /// Creates a new [PdfImage] instance. 35 /// Creates a new [PdfImage] instance.
36 - ///  
37 - /// @param image an [Uint8List] value  
38 - /// @param width  
39 - /// @param height  
40 - /// @param alpha if the image is transparent  
41 factory PdfImage( 36 factory PdfImage(
42 PdfDocument pdfDocument, { 37 PdfDocument pdfDocument, {
43 @required Uint8List image, 38 @required Uint8List image,
@@ -45,68 +40,41 @@ class PdfImage extends PdfXObject { @@ -45,68 +40,41 @@ class PdfImage extends PdfXObject {
45 @required int height, 40 @required int height,
46 bool alpha = true, 41 bool alpha = true,
47 PdfImageOrientation orientation = PdfImageOrientation.topLeft, 42 PdfImageOrientation orientation = PdfImageOrientation.topLeft,
48 - }) =>  
49 - PdfImage._( 43 + }) {
  44 + final PdfImage im = PdfImage._(
50 pdfDocument, 45 pdfDocument,
51 - image: image,  
52 - width: width,  
53 - height: height,  
54 - alpha: alpha,  
55 - alphaChannel: false,  
56 - isRGB: true,  
57 - jpeg: false,  
58 - orientation: orientation, 46 + width,
  47 + height,
  48 + orientation,
59 ); 49 );
60 50
61 - PdfImage._(  
62 - PdfDocument pdfDocument, {  
63 - @required this.image,  
64 - @required int width,  
65 - @required int height,  
66 - @required this.alpha,  
67 - @required this.alphaChannel,  
68 - @required this.isRGB,  
69 - @required this.jpeg,  
70 - @required this.orientation,  
71 - }) : assert(alphaChannel == false || alpha == true),  
72 - assert(width != null),  
73 - assert(height != null),  
74 - assert(jpeg != null),  
75 - assert(isRGB != null),  
76 - assert(orientation != null),  
77 - _width = width,  
78 - _height = height,  
79 - super(pdfDocument, '/Image', isBinary: true) {  
80 - _name = '/Image$objser';  
81 - params['/Width'] = PdfNum(width);  
82 - params['/Height'] = PdfNum(height);  
83 - params['/BitsPerComponent'] = const PdfNum(8);  
84 - params['/Name'] = PdfName(_name);  
85 -  
86 - if (alphaChannel == false && alpha) {  
87 - final PdfImage _sMask = PdfImage._( 51 + im.params['/BitsPerComponent'] = const PdfNum(8);
  52 + im.params['/Name'] = PdfName(im.name);
  53 + im.params['/ColorSpace'] = const PdfName('/DeviceRGB');
  54 +
  55 + if (alpha) {
  56 + final PdfImage _sMask = PdfImage._alpha(
88 pdfDocument, 57 pdfDocument,
89 - image: image,  
90 - width: width,  
91 - height: height,  
92 - alpha: alpha,  
93 - alphaChannel: true,  
94 - isRGB: false,  
95 - jpeg: jpeg,  
96 - orientation: orientation, 58 + image,
  59 + width,
  60 + height,
  61 + orientation,
97 ); 62 );
98 - params['/SMask'] = PdfIndirect(_sMask.objser, 0); 63 + im.params['/SMask'] = PdfIndirect(_sMask.objser, 0);
99 } 64 }
100 65
101 - if (isRGB) {  
102 - params['/ColorSpace'] = const PdfName('/DeviceRGB');  
103 - } else {  
104 - params['/ColorSpace'] = const PdfName('/DeviceGray'); 66 + final int w = width;
  67 + final int h = height;
  68 + final int s = w * h;
  69 + final Uint8List out = Uint8List(s * 3);
  70 + for (int i = 0; i < s; i++) {
  71 + out[i * 3] = image[i * 4];
  72 + out[i * 3 + 1] = image[i * 4 + 1];
  73 + out[i * 3 + 2] = image[i * 4 + 2];
105 } 74 }
106 75
107 - if (jpeg) {  
108 - params['/Intent'] = const PdfName('/RelativeColorimetric');  
109 - } 76 + im.buf.putBytes(out);
  77 + return im;
110 } 78 }
111 79
112 factory PdfImage.jpeg( 80 factory PdfImage.jpeg(
@@ -115,84 +83,83 @@ class PdfImage extends PdfXObject { @@ -115,84 +83,83 @@ class PdfImage extends PdfXObject {
115 PdfImageOrientation orientation, 83 PdfImageOrientation orientation,
116 }) { 84 }) {
117 assert(image != null); 85 assert(image != null);
118 - final PdfJpegInfo info = PdfJpegInfo(image);  
119 86
120 - return PdfImage._( 87 + final PdfJpegInfo info = PdfJpegInfo(image);
  88 + final PdfImage im = PdfImage._(
121 pdfDocument, 89 pdfDocument,
122 - image: image,  
123 - width: info.width,  
124 - height: info.height,  
125 - jpeg: true,  
126 - alpha: false,  
127 - isRGB: info.isRGB,  
128 - alphaChannel: false,  
129 - orientation: orientation ?? info.orientation, 90 + info.width,
  91 + info.height,
  92 + orientation ?? info.orientation,
130 ); 93 );
131 - }  
132 -  
133 - /// RGBA Image Data  
134 - final Uint8List image;  
135 -  
136 - /// Image width  
137 - final int _width;  
138 - int get width => orientation.index >= 4 ? _height : _width;  
139 -  
140 - /// Image height  
141 - final int _height;  
142 - int get height => orientation.index < 4 ? _height : _width;  
143 -  
144 - /// Image has alpha channel  
145 - final bool alpha;  
146 -  
147 - String _name;  
148 94
149 - /// Process alphaChannel only  
150 - final bool alphaChannel; 95 + im.params['/BitsPerComponent'] = const PdfNum(8);
  96 + im.params['/Name'] = PdfName(im.name);
  97 + im.params['/Intent'] = const PdfName('/RelativeColorimetric');
  98 + im.params['/Filter'] = const PdfName('/DCTDecode');
151 99
152 - /// The image data is a jpeg image  
153 - final bool jpeg; 100 + if (info.isRGB) {
  101 + im.params['/ColorSpace'] = const PdfName('/DeviceRGB');
  102 + } else {
  103 + im.params['/ColorSpace'] = const PdfName('/DeviceGray');
  104 + }
154 105
155 - /// The image data is a color RGB image  
156 - final bool isRGB; 106 + im.buf.putBytes(image);
  107 + return im;
  108 + }
157 109
158 - /// The internal orientation of the image  
159 - final PdfImageOrientation orientation; 110 + factory PdfImage._alpha(
  111 + PdfDocument pdfDocument,
  112 + Uint8List image,
  113 + int width,
  114 + int height,
  115 + PdfImageOrientation orientation,
  116 + ) {
  117 + final PdfImage im = PdfImage._(
  118 + pdfDocument,
  119 + width,
  120 + height,
  121 + orientation,
  122 + );
160 123
161 - /// write the pixels to the stream  
162 - @override  
163 - void _prepare() {  
164 - if (jpeg) {  
165 - buf.putBytes(image);  
166 - params['/Filter'] = const PdfName('/DCTDecode');  
167 - super._prepare();  
168 - return;  
169 - } 124 + im.params['/BitsPerComponent'] = const PdfNum(8);
  125 + im.params['/Name'] = PdfName(im.name);
  126 + im.params['/ColorSpace'] = const PdfName('/DeviceGray');
170 127
171 - final int w = _width;  
172 - final int h = _height; 128 + final int w = width;
  129 + final int h = height;
173 final int s = w * h; 130 final int s = w * h;
174 131
175 - final Uint8List out = Uint8List(alphaChannel ? s : s * 3); 132 + final Uint8List out = Uint8List(s);
176 133
177 - if (alphaChannel) {  
178 for (int i = 0; i < s; i++) { 134 for (int i = 0; i < s; i++) {
179 out[i] = image[i * 4 + 3]; 135 out[i] = image[i * 4 + 3];
180 } 136 }
181 - } else {  
182 - for (int i = 0; i < s; i++) {  
183 - out[i * 3] = image[i * 4];  
184 - out[i * 3 + 1] = image[i * 4 + 1];  
185 - out[i * 3 + 2] = image[i * 4 + 2]; 137 +
  138 + im.buf.putBytes(out);
  139 + return im;
186 } 140 }
  141 +
  142 + PdfImage._(
  143 + PdfDocument pdfDocument,
  144 + this._width,
  145 + this._height,
  146 + this.orientation,
  147 + ) : super(pdfDocument, '/Image', isBinary: true) {
  148 + params['/Width'] = PdfNum(_width);
  149 + params['/Height'] = PdfNum(_height);
187 } 150 }
188 151
189 - buf.putBytes(out); 152 + /// Image width
  153 + final int _width;
  154 + int get width => orientation.index >= 4 ? _height : _width;
190 155
191 - super._prepare();  
192 - } 156 + /// Image height
  157 + final int _height;
  158 + int get height => orientation.index < 4 ? _height : _width;
  159 +
  160 + /// The internal orientation of the image
  161 + final PdfImageOrientation orientation;
193 162
194 - /// Get the name  
195 - ///  
196 - /// @return a String value  
197 - String get name => _name; 163 + /// Name of the image
  164 + String get name => '/Image$objser';
198 } 165 }