26
26
* THE SOFTWARE.
27
27
*/
28
28
29
+ #include <string.h>
30
+
31
+ #include "py/gc.h"
29
32
#include "py/runtime.h"
30
33
31
34
#include "shared-module/gifio/GifWriter.h"
35
38
36
39
#define BLOCK_SIZE (126) // (2^7) - 2 // (DO NOT CHANGE!)
37
40
38
- static void handle_error (const char * what , int error ) {
41
+ static void handle_error (gifio_gifwriter_t * self ) {
42
+ if (self -> error != 0 ) {
43
+ mp_raise_OSError (self -> error );
44
+ }
45
+ }
46
+
47
+ static void flush_data (gifio_gifwriter_t * self ) {
48
+ if (self -> cur == 0 ) {
49
+ return ;
50
+ }
51
+ int error = 0 ;
52
+ self -> file_proto -> write (self -> file , self -> data , self -> cur , & error );
53
+ self -> cur = 0 ;
39
54
if (error != 0 ) {
40
- mp_raise_OSError ( error ) ;
55
+ self -> error = error ;
41
56
}
42
57
}
43
58
59
+ // These "write" calls _MUST_ have enough buffer space available! This is
60
+ // ensured by allocating the proper buffer size in construct.
44
61
static void write_data (gifio_gifwriter_t * self , const void * data , size_t size ) {
45
- int error = 0 ;
46
- self -> file_proto -> write ( self -> file , data , size , & error );
47
- handle_error ( "write_data" , error ) ;
62
+ assert ( self -> cur + size <= self -> size ) ;
63
+ memcpy ( self -> data + self -> cur , data , size );
64
+ self -> cur += size ;
48
65
}
49
66
50
67
static void write_byte (gifio_gifwriter_t * self , uint8_t value ) {
@@ -70,23 +87,44 @@ void shared_module_gifio_gifwriter_construct(gifio_gifwriter_t *self, mp_obj_t *
70
87
self -> colorspace = colorspace ;
71
88
self -> own_file = own_file ;
72
89
90
+ size_t nblocks = (width * height + 125 ) / 126 ;
91
+ self -> size = nblocks * 128 + 4 ;
92
+ self -> data = gc_alloc (self -> size , 0 , false);
93
+ self -> cur = 0 ;
94
+ self -> error = 0 ;
95
+
73
96
write_data (self , "GIF89a" , 6 );
74
97
write_word (self , width );
75
98
write_word (self , height );
76
99
write_data (self , (uint8_t []) {0xF6 , 0x00 , 0x00 }, 3 );
77
100
78
- if (colorspace == DISPLAYIO_COLORSPACE_RGB888 ) {
79
- mp_raise_TypeError (translate ("unsupported colorspace for GifWriter" ));
101
+ switch (colorspace ) {
102
+ case DISPLAYIO_COLORSPACE_RGB565 :
103
+ case DISPLAYIO_COLORSPACE_RGB565_SWAPPED :
104
+ case DISPLAYIO_COLORSPACE_BGR565 :
105
+ case DISPLAYIO_COLORSPACE_BGR565_SWAPPED :
106
+ case DISPLAYIO_COLORSPACE_L8 :
107
+ break ;
108
+
109
+ default :
110
+ mp_raise_TypeError (translate ("unsupported colorspace for GifWriter" ));
80
111
}
81
112
82
113
bool color = (colorspace != DISPLAYIO_COLORSPACE_L8 );
83
114
115
+ bool bgr = (colorspace == DISPLAYIO_COLORSPACE_BGR565 || colorspace == DISPLAYIO_COLORSPACE_BGR565_SWAPPED );
116
+ self -> byteswap = (colorspace == DISPLAYIO_COLORSPACE_RGB565_SWAPPED || colorspace == DISPLAYIO_COLORSPACE_BGR565_SWAPPED );
117
+
84
118
if (color ) {
85
119
for (int i = 0 ; i < 128 ; i ++ ) {
86
120
int red = (int )(((((i & 0x60 ) >> 5 ) * 255 ) + 1.5 ) / 3 );
87
121
int green = (int )(((((i & 0x1C ) >> 2 ) * 255 ) + 3.5 ) / 7 );
88
122
int blue = (int )((((i & 0x3 ) * 255 ) + 1.5 ) / 3 );
89
- write_data (self , (uint8_t []) {red , green , blue }, 3 );
123
+ if (bgr ) {
124
+ write_data (self , (uint8_t []) {blue , red , green }, 3 );
125
+ } else {
126
+ write_data (self , (uint8_t []) {red , green , blue }, 3 );
127
+ }
90
128
}
91
129
} else {
92
130
for (int i = 0 ; i < 128 ; i ++ ) {
@@ -101,7 +139,8 @@ void shared_module_gifio_gifwriter_construct(gifio_gifwriter_t *self, mp_obj_t *
101
139
write_data (self , (uint8_t []) {0x03 , 0x01 , 0x00 , 0x00 , 0x00 }, 5 );
102
140
}
103
141
104
-
142
+ flush_data (self );
143
+ handle_error (self );
105
144
}
106
145
107
146
bool shared_module_gifio_gifwriter_deinited (gifio_gifwriter_t * self ) {
@@ -163,36 +202,34 @@ void shared_module_gifio_gifwriter_add_frame(gifio_gifwriter_t *self, const mp_b
163
202
164
203
block_data [0 ] = 1 + block_size ;
165
204
for (int j = 0 ; j < block_size ; j ++ ) {
166
- int pixel = displayio_colorconverter_convert_pixel (self -> colorspace , (* pixels ++ ));
167
- int red = (pixel >> (16 + 6 )) & 0x3 ;
168
- int green = (pixel >> (8 + 5 )) & 0x7 ;
169
- int blue = (pixel >> 6 ) & 0x3 ;
205
+ int pixel = * pixels ++ ;
206
+ if (self -> byteswap ) {
207
+ pixel = __builtin_bswap16 (pixel );
208
+ }
209
+ int red = (pixel >> (11 + (5 - 2 ))) & 0x3 ;
210
+ int green = (pixel >> (5 + (6 - 3 ))) & 0x7 ;
211
+ int blue = (pixel >> (0 + (5 - 2 ))) & 0x3 ;
170
212
block_data [j + 2 ] = (red << 5 ) | (green << 2 ) | blue ;
171
213
}
172
214
write_data (self , block_data , 2 + block_size );
173
215
}
174
216
}
175
217
176
218
write_data (self , (uint8_t []) {0x01 , 0x81 , 0x00 }, 3 ); // end code
177
-
178
- int error = 0 ;
179
- self -> file_proto -> ioctl (self -> file , MP_STREAM_FLUSH , 0 , & error );
180
- handle_error ("flush" , error );
219
+ flush_data (self );
220
+ handle_error (self );
181
221
}
182
222
183
223
void shared_module_gifio_gifwriter_close (gifio_gifwriter_t * self ) {
184
- // we want to ensure the stream is closed even if the first write failed, so we don't use write_data
185
- int error1 = 0 ;
186
- self -> file_proto -> write (self -> file , ";" , 1 , & error1 );
224
+ write_byte (self , ';' );
225
+ flush_data (self );
187
226
188
- int error2 = 0 ;
189
- if (self -> own_file ) {
190
- self -> file_proto -> ioctl (self -> file , MP_STREAM_CLOSE , 0 , & error2 );
191
- } else {
192
- self -> file_proto -> ioctl (self -> file , MP_STREAM_FLUSH , 0 , & error2 );
193
- }
227
+ int error = 0 ;
228
+ self -> file_proto -> ioctl (self -> file , self -> own_file ? MP_STREAM_CLOSE : MP_STREAM_FLUSH , 0 , & error );
194
229
self -> file = NULL ;
195
230
196
- handle_error ("write" , error1 );
197
- handle_error ("close" , error2 );
231
+ if (error != 0 ) {
232
+ self -> error = error ;
233
+ }
234
+ handle_error (self );
198
235
}
0 commit comments