1
1
using System ;
2
- using System . Collections . Generic ;
3
- using System . Linq ;
4
2
using static QRCoder . QRCodeGenerator ;
5
3
6
4
namespace QRCoder ;
@@ -12,6 +10,10 @@ namespace QRCoder;
12
10
// ReSharper disable once InconsistentNaming
13
11
public class BitmapByteQRCode : AbstractQRCode , IDisposable
14
12
{
13
+ private static readonly byte [ ] _bitmapHeaderPart1 = new byte [ ] { 0x42 , 0x4D } ;
14
+ private static readonly byte [ ] _bitmapHeaderPart2 = new byte [ ] { 0x00 , 0x00 , 0x00 , 0x00 , 0x36 , 0x00 , 0x00 , 0x00 , 0x28 , 0x00 , 0x00 , 0x00 } ;
15
+ private static readonly byte [ ] _bitmapHeaderPartEnd = new byte [ ] { 0x01 , 0x00 , 0x18 , 0x00 } ;
16
+
15
17
/// <summary>
16
18
/// Initializes a new instance of the <see cref="BitmapByteQRCode"/> class.
17
19
/// Constructor without parameters to be used in COM objects connections.
@@ -53,54 +55,83 @@ public byte[] GetGraphic(int pixelsPerModule, byte[] darkColorRgb, byte[] lightC
53
55
{
54
56
var sideLength = QrCodeData . ModuleMatrix . Count * pixelsPerModule ;
55
57
56
- var moduleDark = darkColorRgb . Reverse ( ) ;
57
- var moduleLight = lightColorRgb . Reverse ( ) ;
58
+ // Pre-calculate color/module bytes
59
+ byte [ ] moduleDark = new byte [ pixelsPerModule * 3 ] ;
60
+ byte [ ] moduleLight = new byte [ pixelsPerModule * 3 ] ;
61
+ for ( int i = 0 ; i < pixelsPerModule * 3 ; i += 3 )
62
+ {
63
+ moduleDark [ i ] = darkColorRgb [ 2 ] ;
64
+ moduleDark [ i + 1 ] = darkColorRgb [ 1 ] ;
65
+ moduleDark [ i + 2 ] = darkColorRgb [ 0 ] ;
66
+ moduleLight [ i ] = lightColorRgb [ 2 ] ;
67
+ moduleLight [ i + 1 ] = lightColorRgb [ 1 ] ;
68
+ moduleLight [ i + 2 ] = lightColorRgb [ 0 ] ;
69
+ }
70
+
71
+ // Pre-calculate padding bytes
72
+ var paddingLen = sideLength % 4 ;
73
+
74
+ // Calculate filesize (header + pixel data + padding)
75
+ var fileSize = 54 + ( 3 * ( sideLength * sideLength ) ) + ( sideLength * paddingLen ) ;
76
+
77
+ // Bitmap container
78
+ byte [ ] bmp = new byte [ fileSize ] ;
79
+ int ix = 0 ;
80
+
81
+ // Header part 1
82
+ Array . Copy ( _bitmapHeaderPart1 , 0 , bmp , ix , _bitmapHeaderPart1 . Length ) ;
83
+ ix += _bitmapHeaderPart1 . Length ;
84
+
85
+ // Filesize
86
+ CopyIntAs4ByteToArray ( fileSize , ix , bmp ) ;
87
+ ix += 4 ;
58
88
59
- var bmp = new List < byte > ( ) ;
89
+ // Header part 2
90
+ Array . Copy ( _bitmapHeaderPart2 , 0 , bmp , ix , _bitmapHeaderPart2 . Length ) ;
91
+ ix += _bitmapHeaderPart2 . Length ;
60
92
61
- //header
62
- bmp . AddRange ( new byte [ ] { 0x42 , 0x4D , 0x4C , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x36 , 0x00 , 0x00 , 0x00 , 0x28 , 0x00 , 0x00 , 0x00 } ) ;
93
+ // Width
94
+ CopyIntAs4ByteToArray ( sideLength , ix , bmp ) ;
95
+ ix += 4 ;
96
+ // Height
97
+ CopyIntAs4ByteToArray ( sideLength , ix , bmp ) ;
98
+ ix += 4 ;
63
99
64
- //width
65
- bmp . AddRange ( IntTo4Byte ( sideLength ) ) ;
66
- //height
67
- bmp . AddRange ( IntTo4Byte ( sideLength ) ) ;
100
+ // Header end
101
+ Array . Copy ( _bitmapHeaderPartEnd , 0 , bmp , ix , _bitmapHeaderPartEnd . Length ) ;
102
+ ix += _bitmapHeaderPartEnd . Length ;
68
103
69
- //header end
70
- bmp . AddRange ( new byte [ ] { 0x01 , 0x00 , 0x18 , 0x00 } ) ;
71
- bmp . AddRange ( new byte [ 24 ] ) ;
104
+ // Add header null-bytes
105
+ ix += 24 ;
72
106
73
- //draw qr code
107
+
108
+ // Draw qr code
74
109
for ( var x = sideLength - 1 ; x >= 0 ; x -= pixelsPerModule )
75
110
{
76
- for ( int pm = 0 ; pm < pixelsPerModule ; pm ++ )
111
+ var modMatrixX = ( x + pixelsPerModule ) / pixelsPerModule - 1 ;
112
+
113
+ // Write data for first pixel of pixelsPerModule
114
+ int posStartFirstPx = ix ;
115
+ for ( var y = 0 ; y < sideLength ; y += pixelsPerModule )
77
116
{
78
- for ( var y = 0 ; y < sideLength ; y += pixelsPerModule )
79
- {
80
- var module =
81
- QrCodeData . ModuleMatrix [ ( x + pixelsPerModule ) / pixelsPerModule - 1 ] [ ( y + pixelsPerModule ) / pixelsPerModule - 1 ] ;
82
- for ( int i = 0 ; i < pixelsPerModule ; i ++ )
83
- {
84
- bmp . AddRange ( module ? moduleDark : moduleLight ) ;
85
- }
86
- }
87
- if ( sideLength % 4 != 0 )
88
- {
89
- for ( int i = 0 ; i < sideLength % 4 ; i ++ )
90
- {
91
- bmp . Add ( 0x00 ) ;
92
- }
93
- }
117
+ var module = QrCodeData . ModuleMatrix [ modMatrixX ] [ ( y + pixelsPerModule ) / pixelsPerModule - 1 ] ;
118
+ Array . Copy ( module ? moduleDark : moduleLight , 0 , bmp , ix , moduleDark . Length ) ;
119
+ ix += moduleDark . Length ;
94
120
}
95
- }
121
+ // Add padding (to make line length a multiple of 4)
122
+ ix += paddingLen ;
123
+ int lenFirstPx = ix - posStartFirstPx ;
96
124
97
- // write filesize in header
98
- var bmpFileSize = IntTo4Byte ( bmp . Count ) ;
99
- for ( int i = 0 ; i < bmpFileSize . Length ; i ++ )
100
- {
101
- bmp [ 2 + i ] = bmpFileSize [ i ] ;
125
+ // Re-write (copy) first pixel (pixelsPerModule - 1) times
126
+ for ( int pm = 0 ; pm < ( pixelsPerModule - 1 ) ; pm ++ )
127
+ {
128
+ // Draw pixels
129
+ Array . Copy ( bmp , posStartFirstPx , bmp , ix , lenFirstPx ) ;
130
+ ix += lenFirstPx ;
131
+ }
102
132
}
103
- return bmp . ToArray ( ) ;
133
+
134
+ return bmp ;
104
135
}
105
136
106
137
@@ -119,22 +150,22 @@ private byte[] HexColorToByteArray(string colorString)
119
150
return byteColor ;
120
151
}
121
152
153
+
122
154
/// <summary>
123
- /// Converts an integer to a 4- byte array.
155
+ /// Converts an integer to a 4 bytes and writes them to a byte array at given position
124
156
/// </summary>
125
157
/// <param name="inp">The integer to convert.</param>
126
- /// <returns>Returns the integer as a 4-byte array.</returns>
127
- private byte [ ] IntTo4Byte ( int inp )
158
+ /// <param name="destinationIndex">Index of destinationArray where the converted bytes are written to</param>
159
+ /// <param name="destinationArray">Destination byte array that receives the bytes</param>
160
+ private void CopyIntAs4ByteToArray ( int inp , int destinationIndex , byte [ ] destinationArray )
128
161
{
129
- byte [ ] bytes = new byte [ 4 ] ;
130
162
unchecked
131
163
{
132
- bytes [ 3 ] = ( byte ) ( inp >> 24 ) ;
133
- bytes [ 2 ] = ( byte ) ( inp >> 16 ) ;
134
- bytes [ 1 ] = ( byte ) ( inp >> 8 ) ;
135
- bytes [ 0 ] = ( byte ) ( inp ) ;
164
+ destinationArray [ destinationIndex + 3 ] = ( byte ) ( inp >> 24 ) ;
165
+ destinationArray [ destinationIndex + 2 ] = ( byte ) ( inp >> 16 ) ;
166
+ destinationArray [ destinationIndex + 1 ] = ( byte ) ( inp >> 8 ) ;
167
+ destinationArray [ destinationIndex + 0 ] = ( byte ) ( inp ) ;
136
168
}
137
- return bytes ;
138
169
}
139
170
}
140
171
0 commit comments