This is the David Smart RA8875 Library with mods for working with FRDM-K64F

Committer:
WiredHome
Date:
Wed Jul 17 03:02:31 2019 +0000
Revision:
177:d8e65c0e268a
Parent:
152:a013ac0133e4
Child:
196:56820026701b
A little bit of work on GIF, and disable some debug printf's.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 152:a013ac0133e4 1
WiredHome 152:a013ac0133e4 2
WiredHome 152:a013ac0133e4 3
WiredHome 152:a013ac0133e4 4 // GIFRender.cpp : Defines the entry point for the console application.
WiredHome 152:a013ac0133e4 5 //
WiredHome 152:a013ac0133e4 6 // The code in this file was initially found online, in a tutorial.
WiredHome 152:a013ac0133e4 7 // It has been revised significantly in this derivative.
WiredHome 152:a013ac0133e4 8 // No copyright claim was found in the code.
WiredHome 152:a013ac0133e4 9 // http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art011
WiredHome 152:a013ac0133e4 10 //
WiredHome 152:a013ac0133e4 11
WiredHome 152:a013ac0133e4 12 #include "mbed.h"
WiredHome 152:a013ac0133e4 13
WiredHome 152:a013ac0133e4 14 #include "GraphicsDisplay.h"
WiredHome 152:a013ac0133e4 15
WiredHome 152:a013ac0133e4 16
WiredHome 177:d8e65c0e268a 17 //#define DEBUG "GIF_"
WiredHome 152:a013ac0133e4 18 //
WiredHome 152:a013ac0133e4 19 // INFO("Stuff to show %d", var); // new-line is automatically appended
WiredHome 152:a013ac0133e4 20 //
WiredHome 152:a013ac0133e4 21 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 152:a013ac0133e4 22 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 152:a013ac0133e4 23 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 152:a013ac0133e4 24 #define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 152:a013ac0133e4 25 static void HexDump(const char * title, const uint8_t * p, int count) {
WiredHome 152:a013ac0133e4 26 int i;
WiredHome 152:a013ac0133e4 27 char buf[100] = "0000: ";
WiredHome 152:a013ac0133e4 28
WiredHome 152:a013ac0133e4 29 if (*title)
WiredHome 152:a013ac0133e4 30 INFO("%s", title);
WiredHome 152:a013ac0133e4 31 for (i = 0; i<count; ) {
WiredHome 152:a013ac0133e4 32 sprintf(buf + strlen(buf), "%02X ", *(p + i));
WiredHome 152:a013ac0133e4 33 if ((++i & 0x0F) == 0x00) {
WiredHome 152:a013ac0133e4 34 INFO("%s", buf);
WiredHome 152:a013ac0133e4 35 if (i < count)
WiredHome 152:a013ac0133e4 36 sprintf(buf, "%04X: ", i);
WiredHome 152:a013ac0133e4 37 else
WiredHome 152:a013ac0133e4 38 buf[0] = '\0';
WiredHome 152:a013ac0133e4 39 }
WiredHome 152:a013ac0133e4 40 }
WiredHome 152:a013ac0133e4 41 if (strlen(buf))
WiredHome 152:a013ac0133e4 42 INFO("%s", buf);
WiredHome 152:a013ac0133e4 43 }
WiredHome 152:a013ac0133e4 44 #else
WiredHome 152:a013ac0133e4 45 #define INFO(x, ...)
WiredHome 152:a013ac0133e4 46 #define WARN(x, ...)
WiredHome 152:a013ac0133e4 47 #define ERR(x, ...)
WiredHome 152:a013ac0133e4 48 #define HexDump(a, b, c)
WiredHome 152:a013ac0133e4 49 #endif
WiredHome 152:a013ac0133e4 50
WiredHome 152:a013ac0133e4 51
WiredHome 152:a013ac0133e4 52 #define EXTENSION_INTRODUCER 0x21
WiredHome 152:a013ac0133e4 53 #define IMAGE_DESCRIPTOR 0x2C
WiredHome 152:a013ac0133e4 54 #define TRAILER 0x3B
WiredHome 152:a013ac0133e4 55
WiredHome 152:a013ac0133e4 56 #define GRAPHIC_CONTROL 0xF9
WiredHome 152:a013ac0133e4 57 #define APPLICATION_EXTENSION 0xFF
WiredHome 152:a013ac0133e4 58 #define COMMENT_EXTENSION 0xFE
WiredHome 152:a013ac0133e4 59 #define PLAINTEXT_EXTENSION 0x01
WiredHome 152:a013ac0133e4 60
WiredHome 152:a013ac0133e4 61
WiredHome 152:a013ac0133e4 62 typedef struct {
WiredHome 152:a013ac0133e4 63 unsigned char byte;
WiredHome 152:a013ac0133e4 64 int prev;
WiredHome 152:a013ac0133e4 65 int len;
WiredHome 152:a013ac0133e4 66 } dictionary_entry_t;
WiredHome 152:a013ac0133e4 67
WiredHome 152:a013ac0133e4 68 typedef struct {
WiredHome 152:a013ac0133e4 69 unsigned char extension_code;
WiredHome 152:a013ac0133e4 70 unsigned char block_size;
WiredHome 152:a013ac0133e4 71 } extension_t;
WiredHome 152:a013ac0133e4 72 const uint16_t extension_size = 2;
WiredHome 152:a013ac0133e4 73
WiredHome 152:a013ac0133e4 74 typedef struct {
WiredHome 152:a013ac0133e4 75 unsigned char fields;
WiredHome 152:a013ac0133e4 76 unsigned short delay_time;
WiredHome 152:a013ac0133e4 77 unsigned char transparent_color_index;
WiredHome 152:a013ac0133e4 78 } graphic_control_extension_t;
WiredHome 152:a013ac0133e4 79 const uint16_t graphic_control_extension_size = 4;
WiredHome 152:a013ac0133e4 80
WiredHome 152:a013ac0133e4 81 typedef struct {
WiredHome 152:a013ac0133e4 82 unsigned char application_id[8];
WiredHome 152:a013ac0133e4 83 unsigned char version[3];
WiredHome 152:a013ac0133e4 84 } application_extension_t;
WiredHome 152:a013ac0133e4 85 const uint16_t application_extension_size = 11;
WiredHome 152:a013ac0133e4 86
WiredHome 152:a013ac0133e4 87 typedef struct {
WiredHome 152:a013ac0133e4 88 unsigned short left;
WiredHome 152:a013ac0133e4 89 unsigned short top;
WiredHome 152:a013ac0133e4 90 unsigned short width;
WiredHome 152:a013ac0133e4 91 unsigned short height;
WiredHome 152:a013ac0133e4 92 unsigned char cell_width;
WiredHome 152:a013ac0133e4 93 unsigned char cell_height;
WiredHome 152:a013ac0133e4 94 unsigned char foreground_color;
WiredHome 152:a013ac0133e4 95 unsigned char background_color;
WiredHome 152:a013ac0133e4 96 } plaintext_extension_t;
WiredHome 152:a013ac0133e4 97 const uint16_t plaintext_extension_size = 12;
WiredHome 152:a013ac0133e4 98
WiredHome 152:a013ac0133e4 99
WiredHome 152:a013ac0133e4 100 size_t GraphicsDisplay::read_filesystem_bytes(void * buffer, int numBytes, FILE * fh) {
WiredHome 152:a013ac0133e4 101 size_t bytesRead;
WiredHome 152:a013ac0133e4 102
WiredHome 152:a013ac0133e4 103 bytesRead = fread(buffer, 1, numBytes, fh);
WiredHome 152:a013ac0133e4 104 HexDump("mem", (const uint8_t *) buffer, bytesRead);
WiredHome 152:a013ac0133e4 105 return bytesRead;
WiredHome 152:a013ac0133e4 106 }
WiredHome 152:a013ac0133e4 107
WiredHome 152:a013ac0133e4 108
WiredHome 152:a013ac0133e4 109 /// uncompress_gif the data to memory
WiredHome 152:a013ac0133e4 110 ///
WiredHome 152:a013ac0133e4 111 /// @param[in] code_length is the size of this descriptor field
WiredHome 152:a013ac0133e4 112 /// @param[in] input is a pointer to the input data
WiredHome 152:a013ac0133e4 113 /// @param[in] input_length is the number of bytes in the input.
WiredHome 152:a013ac0133e4 114 /// @param[out] out is where the uncompress_gifed information is written.
WiredHome 152:a013ac0133e4 115 /// @return noerror on success, or failure code
WiredHome 152:a013ac0133e4 116 ///
WiredHome 152:a013ac0133e4 117 RetCode_t GraphicsDisplay::uncompress_gif(int code_length, const unsigned char *input, int input_length, unsigned char *out) {
WiredHome 152:a013ac0133e4 118 int i, bit;
WiredHome 152:a013ac0133e4 119 int code, prev = -1;
WiredHome 152:a013ac0133e4 120 dictionary_entry_t * dictionary;
WiredHome 152:a013ac0133e4 121 int dictionary_ind;
WiredHome 152:a013ac0133e4 122 unsigned int mask = 0x01;
WiredHome 152:a013ac0133e4 123 int reset_code_length;
WiredHome 152:a013ac0133e4 124 int clear_code; // This varies depending on code_length
WiredHome 152:a013ac0133e4 125 int stop_code; // one more than clear code
WiredHome 152:a013ac0133e4 126 int match_len;
WiredHome 152:a013ac0133e4 127
WiredHome 152:a013ac0133e4 128 clear_code = 1 << (code_length);
WiredHome 152:a013ac0133e4 129 stop_code = clear_code + 1;
WiredHome 152:a013ac0133e4 130 reset_code_length = code_length;
WiredHome 152:a013ac0133e4 131
WiredHome 152:a013ac0133e4 132 // Create a dictionary large enough to hold "code_length" entries.
WiredHome 152:a013ac0133e4 133 // Once the dictionary overflows, code_length increases
WiredHome 177:d8e65c0e268a 134 size_t bytes = sizeof(dictionary_entry_t) * (1 << (code_length + 1));
WiredHome 177:d8e65c0e268a 135 INFO("uncompress_gif malloc(%d)", bytes);
WiredHome 177:d8e65c0e268a 136 dictionary = (dictionary_entry_t *) malloc(bytes);
WiredHome 177:d8e65c0e268a 137 if (dictionary == NULL) {
WiredHome 152:a013ac0133e4 138 return not_enough_ram;
WiredHome 177:d8e65c0e268a 139 }
WiredHome 152:a013ac0133e4 140 // Initialize the first 2^code_len entries of the dictionary with their
WiredHome 152:a013ac0133e4 141 // indices. The rest of the entries will be built up dynamically.
WiredHome 152:a013ac0133e4 142
WiredHome 152:a013ac0133e4 143 // Technically, it shouldn't be necessary to initialize the
WiredHome 152:a013ac0133e4 144 // dictionary. The spec says that the encoder "should output a
WiredHome 152:a013ac0133e4 145 // clear code as the first code in the image data stream". It doesn't
WiredHome 152:a013ac0133e4 146 // say must, though...
WiredHome 152:a013ac0133e4 147 for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
WiredHome 152:a013ac0133e4 148 dictionary[dictionary_ind].byte = (uint8_t) dictionary_ind;
WiredHome 152:a013ac0133e4 149 // XXX this only works because prev is a 32-bit int (> 12 bits)
WiredHome 152:a013ac0133e4 150 dictionary[dictionary_ind].prev = -1;
WiredHome 152:a013ac0133e4 151 dictionary[dictionary_ind].len = 1;
WiredHome 152:a013ac0133e4 152 }
WiredHome 152:a013ac0133e4 153 // 2^code_len + 1 is the special "end" code; don't give it an entry here
WiredHome 152:a013ac0133e4 154 dictionary_ind++;
WiredHome 152:a013ac0133e4 155 dictionary_ind++;
WiredHome 152:a013ac0133e4 156
WiredHome 152:a013ac0133e4 157 // TODO verify that the very last byte is clear_code + 1
WiredHome 152:a013ac0133e4 158 while (input_length) {
WiredHome 152:a013ac0133e4 159 code = 0x0;
WiredHome 152:a013ac0133e4 160 // Always read one more bit than the code length
WiredHome 152:a013ac0133e4 161 for (i = 0; i < (code_length + 1); i++) {
WiredHome 152:a013ac0133e4 162 // This is different than in the file read example; that
WiredHome 152:a013ac0133e4 163 // was a call to "next_bit"
WiredHome 152:a013ac0133e4 164 bit = (*input & mask) ? 1 : 0;
WiredHome 152:a013ac0133e4 165 mask <<= 1;
WiredHome 152:a013ac0133e4 166 if (mask == 0x100) {
WiredHome 152:a013ac0133e4 167 mask = 0x01;
WiredHome 152:a013ac0133e4 168 input++;
WiredHome 152:a013ac0133e4 169 input_length--;
WiredHome 152:a013ac0133e4 170 }
WiredHome 152:a013ac0133e4 171 code = code | (bit << i);
WiredHome 152:a013ac0133e4 172 }
WiredHome 152:a013ac0133e4 173 if (code == clear_code) {
WiredHome 152:a013ac0133e4 174 code_length = reset_code_length;
WiredHome 152:a013ac0133e4 175 dictionary = (dictionary_entry_t *) realloc(dictionary,
WiredHome 152:a013ac0133e4 176 sizeof(dictionary_entry_t) * (1 << (code_length + 1)));
WiredHome 152:a013ac0133e4 177 for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
WiredHome 152:a013ac0133e4 178 dictionary[dictionary_ind].byte = (uint8_t) dictionary_ind;
WiredHome 152:a013ac0133e4 179 // XXX this only works because prev is a 32-bit int (> 12 bits)
WiredHome 152:a013ac0133e4 180 dictionary[dictionary_ind].prev = -1;
WiredHome 152:a013ac0133e4 181 dictionary[dictionary_ind].len = 1;
WiredHome 152:a013ac0133e4 182 }
WiredHome 152:a013ac0133e4 183 dictionary_ind++;
WiredHome 152:a013ac0133e4 184 dictionary_ind++;
WiredHome 152:a013ac0133e4 185 prev = -1;
WiredHome 152:a013ac0133e4 186 continue;
WiredHome 152:a013ac0133e4 187 } else if (code == stop_code) {
WiredHome 152:a013ac0133e4 188 if (input_length > 1) {
WiredHome 152:a013ac0133e4 189 free(dictionary);
WiredHome 152:a013ac0133e4 190 return not_supported_format;
WiredHome 152:a013ac0133e4 191 }
WiredHome 152:a013ac0133e4 192 break;
WiredHome 152:a013ac0133e4 193 }
WiredHome 152:a013ac0133e4 194
WiredHome 152:a013ac0133e4 195 // Update the dictionary with this character plus the _entry_
WiredHome 152:a013ac0133e4 196 // (character or string) that came before it
WiredHome 152:a013ac0133e4 197 if ((prev > -1) && (code_length < 12)) {
WiredHome 152:a013ac0133e4 198 if (code > dictionary_ind) {
WiredHome 152:a013ac0133e4 199 //fprintf(stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind);
WiredHome 152:a013ac0133e4 200 free(dictionary);
WiredHome 152:a013ac0133e4 201 return not_supported_format;
WiredHome 152:a013ac0133e4 202 }
WiredHome 152:a013ac0133e4 203 if (code == dictionary_ind) {
WiredHome 152:a013ac0133e4 204 int ptr = prev;
WiredHome 152:a013ac0133e4 205
WiredHome 152:a013ac0133e4 206 while (dictionary[ptr].prev != -1) {
WiredHome 152:a013ac0133e4 207 ptr = dictionary[ptr].prev;
WiredHome 152:a013ac0133e4 208 }
WiredHome 152:a013ac0133e4 209 dictionary[dictionary_ind].byte = dictionary[ptr].byte;
WiredHome 152:a013ac0133e4 210 } else {
WiredHome 152:a013ac0133e4 211 int ptr = code;
WiredHome 152:a013ac0133e4 212 while (dictionary[ptr].prev != -1) {
WiredHome 152:a013ac0133e4 213 ptr = dictionary[ptr].prev;
WiredHome 152:a013ac0133e4 214 }
WiredHome 152:a013ac0133e4 215 dictionary[dictionary_ind].byte = dictionary[ptr].byte;
WiredHome 152:a013ac0133e4 216 }
WiredHome 152:a013ac0133e4 217 dictionary[dictionary_ind].prev = prev;
WiredHome 152:a013ac0133e4 218 dictionary[dictionary_ind].len = dictionary[prev].len + 1;
WiredHome 152:a013ac0133e4 219 dictionary_ind++;
WiredHome 152:a013ac0133e4 220 // GIF89a mandates that this stops at 12 bits
WiredHome 152:a013ac0133e4 221 if ((dictionary_ind == (1 << (code_length + 1))) &&
WiredHome 152:a013ac0133e4 222 (code_length < 11)) {
WiredHome 152:a013ac0133e4 223 code_length++;
WiredHome 152:a013ac0133e4 224 dictionary = (dictionary_entry_t *) realloc(dictionary,
WiredHome 152:a013ac0133e4 225 sizeof(dictionary_entry_t) * (1 << (code_length + 1)));
WiredHome 152:a013ac0133e4 226 }
WiredHome 152:a013ac0133e4 227 }
WiredHome 152:a013ac0133e4 228 prev = code;
WiredHome 152:a013ac0133e4 229 // Now copy the dictionary entry backwards into "out"
WiredHome 152:a013ac0133e4 230 match_len = dictionary[code].len;
WiredHome 152:a013ac0133e4 231 while (code != -1) {
WiredHome 152:a013ac0133e4 232 int pos = dictionary[code].len - 1;
WiredHome 152:a013ac0133e4 233 out[pos] = dictionary[code].byte;
WiredHome 177:d8e65c0e268a 234 //INFO("%p out[%d] = %02X", out, pos, out[pos]);
WiredHome 152:a013ac0133e4 235 if (dictionary[code].prev == code) {
WiredHome 152:a013ac0133e4 236 free(dictionary);
WiredHome 152:a013ac0133e4 237 return not_supported_format;
WiredHome 152:a013ac0133e4 238 }
WiredHome 152:a013ac0133e4 239 code = dictionary[code].prev;
WiredHome 152:a013ac0133e4 240 }
WiredHome 152:a013ac0133e4 241 out += match_len;
WiredHome 152:a013ac0133e4 242 }
WiredHome 152:a013ac0133e4 243 free(dictionary);
WiredHome 152:a013ac0133e4 244 return noerror;
WiredHome 152:a013ac0133e4 245 }
WiredHome 152:a013ac0133e4 246
WiredHome 152:a013ac0133e4 247
WiredHome 152:a013ac0133e4 248 /// read a block
WiredHome 152:a013ac0133e4 249 ///
WiredHome 152:a013ac0133e4 250 /// @param[in] fh is the handle to the gif file.
WiredHome 152:a013ac0133e4 251 /// @param[in] data is a pointer to a pointer to the data being processed.
WiredHome 152:a013ac0133e4 252 /// @return -1 on failure, 0 when done, or >0 as the length of a processed data block
WiredHome 152:a013ac0133e4 253 ///
WiredHome 152:a013ac0133e4 254 int GraphicsDisplay::read_gif_sub_blocks(FILE * fh, unsigned char **data) {
WiredHome 152:a013ac0133e4 255 int data_length;
WiredHome 152:a013ac0133e4 256 int index;
WiredHome 152:a013ac0133e4 257 unsigned char block_size;
WiredHome 152:a013ac0133e4 258
WiredHome 152:a013ac0133e4 259 // Everything following are data sub-blocks, until a 0-sized block is encountered.
WiredHome 152:a013ac0133e4 260 data_length = 0;
WiredHome 152:a013ac0133e4 261 *data = NULL;
WiredHome 152:a013ac0133e4 262 index = 0;
WiredHome 152:a013ac0133e4 263
WiredHome 152:a013ac0133e4 264 while (1) {
WiredHome 152:a013ac0133e4 265 if (read_filesystem_bytes(&block_size, 1, fh) < 1) {
WiredHome 152:a013ac0133e4 266 return -1;
WiredHome 152:a013ac0133e4 267 }
WiredHome 152:a013ac0133e4 268 if (block_size == 0) {
WiredHome 152:a013ac0133e4 269 break;
WiredHome 152:a013ac0133e4 270 }
WiredHome 152:a013ac0133e4 271 data_length += block_size;
WiredHome 152:a013ac0133e4 272 *data = (unsigned char *) realloc(*data, data_length);
WiredHome 152:a013ac0133e4 273 if (data) {
WiredHome 152:a013ac0133e4 274 if (read_filesystem_bytes(*data + index, block_size, fh) < block_size) {
WiredHome 152:a013ac0133e4 275 return -1;
WiredHome 152:a013ac0133e4 276 }
WiredHome 152:a013ac0133e4 277 index += block_size;
WiredHome 152:a013ac0133e4 278 } else {
WiredHome 152:a013ac0133e4 279 return -1;
WiredHome 152:a013ac0133e4 280 }
WiredHome 152:a013ac0133e4 281 }
WiredHome 152:a013ac0133e4 282 return data_length;
WiredHome 152:a013ac0133e4 283 }
WiredHome 152:a013ac0133e4 284
WiredHome 152:a013ac0133e4 285 // color table is encoded as 24-bit values, but we don't need that much space, since
WiredHome 152:a013ac0133e4 286 // the RA8875 is configured as either 8 or 16-bit color.
WiredHome 152:a013ac0133e4 287 //
WiredHome 152:a013ac0133e4 288 RetCode_t GraphicsDisplay::readColorTable(color_t * colorTable, int colorTableSize, FILE * fh) {
WiredHome 152:a013ac0133e4 289 struct {
WiredHome 152:a013ac0133e4 290 uint8_t r;
WiredHome 152:a013ac0133e4 291 uint8_t g;
WiredHome 152:a013ac0133e4 292 uint8_t b;
WiredHome 152:a013ac0133e4 293 } rgb;
WiredHome 152:a013ac0133e4 294 while (colorTableSize--) {
WiredHome 152:a013ac0133e4 295 if (read_filesystem_bytes(&rgb, 3, fh) < 3)
WiredHome 152:a013ac0133e4 296 return not_supported_format;
WiredHome 152:a013ac0133e4 297 *colorTable++ = RGB(rgb.r, rgb.g, rgb.b);
WiredHome 152:a013ac0133e4 298 }
WiredHome 152:a013ac0133e4 299 return noerror;
WiredHome 152:a013ac0133e4 300 }
WiredHome 152:a013ac0133e4 301
WiredHome 152:a013ac0133e4 302 RetCode_t GraphicsDisplay::readGIFImageDescriptor(FILE * fh, gif_image_descriptor_t * imageDescriptor) {
WiredHome 152:a013ac0133e4 303 if (read_filesystem_bytes(imageDescriptor, gif_image_descriptor_size, fh) < gif_image_descriptor_size)
WiredHome 152:a013ac0133e4 304 return not_supported_format;
WiredHome 177:d8e65c0e268a 305 INFO("gif_image_descriptor");
WiredHome 177:d8e65c0e268a 306 INFO(" left: %d", imageDescriptor->image_left_position);
WiredHome 177:d8e65c0e268a 307 INFO(" top: %d", imageDescriptor->image_top_position);
WiredHome 177:d8e65c0e268a 308 INFO(" width: %d", imageDescriptor->image_width);
WiredHome 177:d8e65c0e268a 309 INFO(" height: %d", imageDescriptor->image_height);
WiredHome 177:d8e65c0e268a 310 INFO(" fields: %02Xx", imageDescriptor->fields);
WiredHome 177:d8e65c0e268a 311 INFO(" lct: %2d", (imageDescriptor->fields & 0x80) ? 1 : 0);
WiredHome 177:d8e65c0e268a 312 INFO(" res: %2d", (imageDescriptor->fields & 0x40) ? 1 : 0);
WiredHome 177:d8e65c0e268a 313 INFO(" sort: %2d", (imageDescriptor->fields & 0x20) ? 1 : 0);
WiredHome 177:d8e65c0e268a 314 INFO(" res: %2d", ((imageDescriptor->fields & 0x18) >> 3));
WiredHome 177:d8e65c0e268a 315 INFO("locclrtbl siz: %2d", 1 << ((imageDescriptor->fields & 0x07) + 1));
WiredHome 152:a013ac0133e4 316 if (imageDescriptor->fields & 0x80) {
WiredHome 152:a013ac0133e4 317 local_color_table_size = 1 << ((imageDescriptor->fields & 0x07) + 1);
WiredHome 152:a013ac0133e4 318 local_color_table = (color_t *) malloc(sizeof(color_t) * local_color_table_size);
WiredHome 152:a013ac0133e4 319 if (local_color_table == NULL)
WiredHome 152:a013ac0133e4 320 return not_enough_ram;
WiredHome 152:a013ac0133e4 321 if (readColorTable(local_color_table, local_color_table_size, fh) != noerror) {
WiredHome 152:a013ac0133e4 322 free(local_color_table);
WiredHome 152:a013ac0133e4 323 local_color_table = NULL;
WiredHome 152:a013ac0133e4 324 return not_supported_format;
WiredHome 152:a013ac0133e4 325 }
WiredHome 152:a013ac0133e4 326 }
WiredHome 177:d8e65c0e268a 327 INFO("gif_image_descriptor end.");
WiredHome 152:a013ac0133e4 328 return noerror;
WiredHome 152:a013ac0133e4 329 }
WiredHome 152:a013ac0133e4 330
WiredHome 152:a013ac0133e4 331 /// Process the image section of the GIF file
WiredHome 152:a013ac0133e4 332 ///
WiredHome 152:a013ac0133e4 333 /// @param[in] fh is the handle to the file.
WiredHome 152:a013ac0133e4 334 /// @param[in] uncompress_gifed_data is a pointer to a pointer to where the data will be placed.
WiredHome 152:a013ac0133e4 335 /// @returns true if all went well.
WiredHome 152:a013ac0133e4 336 ///
WiredHome 152:a013ac0133e4 337 RetCode_t GraphicsDisplay::process_gif_image_descriptor(FILE * fh, uint8_t ** uncompress_gifed_data, int width, int height) {
WiredHome 152:a013ac0133e4 338 int compressed_data_length;
WiredHome 152:a013ac0133e4 339 unsigned char *compressed_data = NULL;
WiredHome 152:a013ac0133e4 340 unsigned char lzw_code_size;
WiredHome 152:a013ac0133e4 341 int uncompress_gifed_data_length = 0;
WiredHome 152:a013ac0133e4 342 RetCode_t res = not_supported_format;
WiredHome 152:a013ac0133e4 343 local_color_table_size = 0;
WiredHome 152:a013ac0133e4 344
WiredHome 152:a013ac0133e4 345 if (read_filesystem_bytes(&lzw_code_size, 1, fh) < 1)
WiredHome 152:a013ac0133e4 346 goto done;
WiredHome 177:d8e65c0e268a 347 INFO("lzw_code_size %d", lzw_code_size);
WiredHome 152:a013ac0133e4 348 compressed_data_length = read_gif_sub_blocks(fh, &compressed_data);
WiredHome 152:a013ac0133e4 349 if (compressed_data_length > 0) {
WiredHome 152:a013ac0133e4 350 uncompress_gifed_data_length = width * height;
WiredHome 177:d8e65c0e268a 351 *uncompress_gifed_data = (unsigned char *)malloc(uncompress_gifed_data_length);
WiredHome 177:d8e65c0e268a 352 if (*uncompress_gifed_data == NULL) {
WiredHome 152:a013ac0133e4 353 return not_enough_ram;
WiredHome 177:d8e65c0e268a 354 }
WiredHome 152:a013ac0133e4 355 res = uncompress_gif(lzw_code_size, compressed_data, compressed_data_length, *uncompress_gifed_data);
WiredHome 152:a013ac0133e4 356 }
WiredHome 152:a013ac0133e4 357 done:
WiredHome 152:a013ac0133e4 358 if (compressed_data)
WiredHome 152:a013ac0133e4 359 free(compressed_data);
WiredHome 177:d8e65c0e268a 360 INFO("lzw_code_size end %d", res);
WiredHome 152:a013ac0133e4 361 return res;
WiredHome 152:a013ac0133e4 362 }
WiredHome 152:a013ac0133e4 363
WiredHome 152:a013ac0133e4 364
WiredHome 152:a013ac0133e4 365 int GraphicsDisplay::process_gif_extension(FILE * fh) {
WiredHome 152:a013ac0133e4 366 extension_t extension;
WiredHome 152:a013ac0133e4 367 graphic_control_extension_t gce;
WiredHome 152:a013ac0133e4 368 application_extension_t application;
WiredHome 152:a013ac0133e4 369 plaintext_extension_t plaintext;
WiredHome 152:a013ac0133e4 370 unsigned char *extension_data = NULL;
WiredHome 152:a013ac0133e4 371 /* int extension_data_length; */
WiredHome 152:a013ac0133e4 372
WiredHome 152:a013ac0133e4 373 if (read_filesystem_bytes(&extension, extension_size, fh) < extension_size) {
WiredHome 152:a013ac0133e4 374 return 0;
WiredHome 152:a013ac0133e4 375 }
WiredHome 177:d8e65c0e268a 376 INFO("extension");
WiredHome 177:d8e65c0e268a 377 INFO(" code: %d", extension.extension_code);
WiredHome 177:d8e65c0e268a 378 INFO(" block size: %d", extension.block_size);
WiredHome 152:a013ac0133e4 379 switch (extension.extension_code) {
WiredHome 152:a013ac0133e4 380 case GRAPHIC_CONTROL:
WiredHome 152:a013ac0133e4 381 if (read_filesystem_bytes(&gce, graphic_control_extension_size, fh) < graphic_control_extension_size) {
WiredHome 152:a013ac0133e4 382 return 0;
WiredHome 152:a013ac0133e4 383 }
WiredHome 177:d8e65c0e268a 384 INFO("graphic_control_extension");
WiredHome 177:d8e65c0e268a 385 INFO(" fields: %d", gce.fields);
WiredHome 177:d8e65c0e268a 386 INFO(" delay time: %d", gce.delay_time);
WiredHome 177:d8e65c0e268a 387 INFO(" transparent: %d", gce.transparent_color_index);
WiredHome 152:a013ac0133e4 388 break;
WiredHome 152:a013ac0133e4 389 case APPLICATION_EXTENSION:
WiredHome 152:a013ac0133e4 390 if (read_filesystem_bytes(&application, application_extension_size, fh) < application_extension_size) {
WiredHome 152:a013ac0133e4 391 return 0;
WiredHome 152:a013ac0133e4 392 }
WiredHome 152:a013ac0133e4 393 HexDump("application", (const uint8_t *) &application, sizeof(application));
WiredHome 152:a013ac0133e4 394 break;
WiredHome 152:a013ac0133e4 395 case COMMENT_EXTENSION:
WiredHome 152:a013ac0133e4 396 // comment extension; do nothing - all the data is in the
WiredHome 152:a013ac0133e4 397 // sub-blocks that follow.
WiredHome 152:a013ac0133e4 398 break;
WiredHome 152:a013ac0133e4 399 case PLAINTEXT_EXTENSION:
WiredHome 152:a013ac0133e4 400 if (read_filesystem_bytes(&plaintext, plaintext_extension_size, fh) < plaintext_extension_size) {
WiredHome 152:a013ac0133e4 401 return 0;
WiredHome 152:a013ac0133e4 402 }
WiredHome 152:a013ac0133e4 403 HexDump("plaintext", (const uint8_t *) &plaintext, sizeof(plaintext));
WiredHome 152:a013ac0133e4 404 break;
WiredHome 152:a013ac0133e4 405 default:
WiredHome 152:a013ac0133e4 406 return (0);
WiredHome 152:a013ac0133e4 407 }
WiredHome 152:a013ac0133e4 408 // All extensions are followed by data sub-blocks; even if it's
WiredHome 152:a013ac0133e4 409 // just a single data sub-block of length 0
WiredHome 152:a013ac0133e4 410 /* extension_data_length = */ read_gif_sub_blocks(fh, &extension_data);
WiredHome 152:a013ac0133e4 411 if (extension_data != NULL)
WiredHome 152:a013ac0133e4 412 free(extension_data);
WiredHome 152:a013ac0133e4 413 return 1;
WiredHome 152:a013ac0133e4 414 }
WiredHome 152:a013ac0133e4 415
WiredHome 152:a013ac0133e4 416
WiredHome 152:a013ac0133e4 417 RetCode_t GraphicsDisplay::_RenderGIF(loc_t ScreenX, loc_t ScreenY, FILE * fh) {
WiredHome 152:a013ac0133e4 418 //int color_resolution_bits;
WiredHome 152:a013ac0133e4 419 global_color_table_size = 0;
WiredHome 152:a013ac0133e4 420 local_color_table_size = 0;
WiredHome 152:a013ac0133e4 421
WiredHome 152:a013ac0133e4 422 if (GetGIFHeader(fh) != noerror)
WiredHome 152:a013ac0133e4 423 return not_supported_format;
WiredHome 152:a013ac0133e4 424 //color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
WiredHome 152:a013ac0133e4 425 if (screen_descriptor.fields & 0x80) {
WiredHome 152:a013ac0133e4 426 // If bit 7 is set, the next block is a global color table; read it
WiredHome 152:a013ac0133e4 427 global_color_table_size = 1 << ((screen_descriptor.fields & 0x07) + 1);
WiredHome 152:a013ac0133e4 428 global_color_table = (color_t *) malloc(sizeof(color_t) * global_color_table_size);
WiredHome 152:a013ac0133e4 429 if (global_color_table == NULL)
WiredHome 152:a013ac0133e4 430 return not_enough_ram;
WiredHome 152:a013ac0133e4 431 // XXX this could conceivably return a short count...
WiredHome 152:a013ac0133e4 432 if (readColorTable(global_color_table, global_color_table_size, fh) != noerror) {
WiredHome 152:a013ac0133e4 433 return not_supported_format;
WiredHome 152:a013ac0133e4 434 }
WiredHome 152:a013ac0133e4 435 HexDump("Global Color Table", (const uint8_t *) global_color_table, 3 * global_color_table_size);
WiredHome 152:a013ac0133e4 436 }
WiredHome 152:a013ac0133e4 437 unsigned char block_type = 0x0;
WiredHome 152:a013ac0133e4 438 uint8_t * uncompress_gifed_data = NULL;
WiredHome 152:a013ac0133e4 439 gif_image_descriptor_t gif_image_descriptor; // the image fragment
WiredHome 152:a013ac0133e4 440 while (block_type != TRAILER) {
WiredHome 152:a013ac0133e4 441 if (read_filesystem_bytes(&block_type, sizeof(block_type), fh) < sizeof(block_type))
WiredHome 152:a013ac0133e4 442 return not_supported_format;
WiredHome 152:a013ac0133e4 443 INFO("block type: %02X", block_type);
WiredHome 152:a013ac0133e4 444
WiredHome 177:d8e65c0e268a 445 RetCode_t r_pgid = noerror;
WiredHome 152:a013ac0133e4 446 switch (block_type) {
WiredHome 152:a013ac0133e4 447 case IMAGE_DESCRIPTOR:
WiredHome 177:d8e65c0e268a 448 if (readGIFImageDescriptor(fh, &gif_image_descriptor) != noerror) {
WiredHome 177:d8e65c0e268a 449 INFO("not supported format");
WiredHome 152:a013ac0133e4 450 return not_supported_format;
WiredHome 177:d8e65c0e268a 451 }
WiredHome 177:d8e65c0e268a 452 r_pgid = process_gif_image_descriptor(fh, &uncompress_gifed_data, gif_image_descriptor.image_width, gif_image_descriptor.image_height);
WiredHome 177:d8e65c0e268a 453 if (r_pgid != noerror) {
WiredHome 177:d8e65c0e268a 454 INFO("error %d", r_pgid);
WiredHome 177:d8e65c0e268a 455 return r_pgid;
WiredHome 177:d8e65c0e268a 456 } else {
WiredHome 152:a013ac0133e4 457 if (uncompress_gifed_data) {
WiredHome 152:a013ac0133e4 458 // Ready to render to the screen
WiredHome 177:d8e65c0e268a 459 INFO("Render to (%d,%d)", ScreenX, ScreenY);
WiredHome 152:a013ac0133e4 460 color_t * active_color_table = (local_color_table) ? local_color_table : global_color_table;
WiredHome 152:a013ac0133e4 461
WiredHome 152:a013ac0133e4 462 // create a local image buffer for this fragment
WiredHome 152:a013ac0133e4 463 color_t * cbmp = (color_t *) malloc(sizeof(color_t) * gif_image_descriptor.image_width * gif_image_descriptor.image_height);
WiredHome 177:d8e65c0e268a 464 if (cbmp == NULL) {
WiredHome 177:d8e65c0e268a 465 INFO("not enough ram");
WiredHome 152:a013ac0133e4 466 return not_enough_ram;
WiredHome 177:d8e65c0e268a 467 }
WiredHome 152:a013ac0133e4 468 for (int i = 0; i < gif_image_descriptor.image_width * gif_image_descriptor.image_height; i++) {
WiredHome 152:a013ac0133e4 469 int cIndex = uncompress_gifed_data[i];
WiredHome 152:a013ac0133e4 470 cbmp[i] = active_color_table[cIndex];
WiredHome 152:a013ac0133e4 471 }
WiredHome 152:a013ac0133e4 472 // Write Fragment to Screen
WiredHome 152:a013ac0133e4 473 #if 0
WiredHome 177:d8e65c0e268a 474 INFO("Render fragment: (%d,%d), offset: (%d,%d), w x h (%d,%d)",
WiredHome 152:a013ac0133e4 475 ScreenX, ScreenY,
WiredHome 152:a013ac0133e4 476 gif_image_descriptor.image_left_position,
WiredHome 152:a013ac0133e4 477 gif_image_descriptor.image_top_position,
WiredHome 152:a013ac0133e4 478 gif_image_descriptor.image_width,
WiredHome 152:a013ac0133e4 479 gif_image_descriptor.image_height);
WiredHome 152:a013ac0133e4 480 for (uint16_t y = 0; y < gif_image_descriptor.image_height; y++) {
WiredHome 152:a013ac0133e4 481 for (uint16_t x = 0; x < gif_image_descriptor.image_width; x++) {
WiredHome 152:a013ac0133e4 482 INFO("%04X ", cbmp[y * gif_image_descriptor.image_height + x]);
WiredHome 152:a013ac0133e4 483 }
WiredHome 177:d8e65c0e268a 484 INFO("");
WiredHome 152:a013ac0133e4 485 }
WiredHome 152:a013ac0133e4 486 #else
WiredHome 152:a013ac0133e4 487 rect_t restore = windowrect;
WiredHome 152:a013ac0133e4 488 window(ScreenX + gif_image_descriptor.image_left_position,
WiredHome 152:a013ac0133e4 489 ScreenY + gif_image_descriptor.image_top_position,
WiredHome 152:a013ac0133e4 490 gif_image_descriptor.image_width,
WiredHome 152:a013ac0133e4 491 gif_image_descriptor.image_height);
WiredHome 152:a013ac0133e4 492 pixelStream(cbmp, screen_descriptor.width * screen_descriptor.height,
WiredHome 152:a013ac0133e4 493 ScreenX + gif_image_descriptor.image_left_position,
WiredHome 152:a013ac0133e4 494 ScreenY + gif_image_descriptor.image_top_position);
WiredHome 152:a013ac0133e4 495 window(restore);
WiredHome 152:a013ac0133e4 496 #endif
WiredHome 152:a013ac0133e4 497 // end write
WiredHome 152:a013ac0133e4 498 free(cbmp);
WiredHome 152:a013ac0133e4 499 }
WiredHome 152:a013ac0133e4 500 if (local_color_table) {
WiredHome 152:a013ac0133e4 501 free(local_color_table);
WiredHome 152:a013ac0133e4 502 local_color_table = NULL;
WiredHome 152:a013ac0133e4 503 }
WiredHome 152:a013ac0133e4 504 }
WiredHome 152:a013ac0133e4 505 break;
WiredHome 152:a013ac0133e4 506 case EXTENSION_INTRODUCER:
WiredHome 177:d8e65c0e268a 507 if (!process_gif_extension(fh)) {
WiredHome 177:d8e65c0e268a 508 INFO("not supported format");
WiredHome 152:a013ac0133e4 509 return not_supported_format;
WiredHome 177:d8e65c0e268a 510 }
WiredHome 152:a013ac0133e4 511 break;
WiredHome 152:a013ac0133e4 512 case TRAILER:
WiredHome 152:a013ac0133e4 513 break;
WiredHome 152:a013ac0133e4 514 default:
WiredHome 177:d8e65c0e268a 515 INFO("not supported format");
WiredHome 152:a013ac0133e4 516 return not_supported_format;
WiredHome 152:a013ac0133e4 517 }
WiredHome 152:a013ac0133e4 518 }
WiredHome 177:d8e65c0e268a 519 INFO("no error");
WiredHome 152:a013ac0133e4 520 return noerror;
WiredHome 152:a013ac0133e4 521 }
WiredHome 152:a013ac0133e4 522
WiredHome 152:a013ac0133e4 523
WiredHome 152:a013ac0133e4 524 // hasGIFHeader determines if it is a GIF file
WiredHome 152:a013ac0133e4 525 //
WiredHome 152:a013ac0133e4 526 // This reads a few bytes of the file and determines if they have the
WiredHome 152:a013ac0133e4 527 // GIF89a signature. GIF87a is not supported.
WiredHome 152:a013ac0133e4 528 //
WiredHome 152:a013ac0133e4 529 // @param fh is a file handle.
WiredHome 152:a013ac0133e4 530 // @returns true if it is GIF89a.
WiredHome 152:a013ac0133e4 531 //
WiredHome 152:a013ac0133e4 532 bool GraphicsDisplay::hasGIFHeader(FILE * fh) {
WiredHome 152:a013ac0133e4 533 char GIF_Header[6];
WiredHome 152:a013ac0133e4 534 if (read_filesystem_bytes(GIF_Header, sizeof(GIF_Header), fh) != sizeof(GIF_Header))
WiredHome 152:a013ac0133e4 535 return false;
WiredHome 152:a013ac0133e4 536 if (strncmp("GIF89a", GIF_Header, sizeof(GIF_Header)))
WiredHome 152:a013ac0133e4 537 return false;
WiredHome 152:a013ac0133e4 538 return true;
WiredHome 152:a013ac0133e4 539 }
WiredHome 152:a013ac0133e4 540
WiredHome 152:a013ac0133e4 541
WiredHome 152:a013ac0133e4 542 RetCode_t GraphicsDisplay::GetGIFHeader(FILE * fh) {
WiredHome 152:a013ac0133e4 543 if (read_filesystem_bytes(&screen_descriptor, gif_screen_descriptor_size, fh) < gif_screen_descriptor_size) {
WiredHome 152:a013ac0133e4 544 return not_supported_format;
WiredHome 152:a013ac0133e4 545 }
WiredHome 152:a013ac0133e4 546 screen_descriptor_isvalid = true;
WiredHome 177:d8e65c0e268a 547 INFO("screen_descriptor");
WiredHome 177:d8e65c0e268a 548 INFO(" width: %d", screen_descriptor.width);
WiredHome 177:d8e65c0e268a 549 INFO(" height: %d", screen_descriptor.height);
WiredHome 177:d8e65c0e268a 550 INFO(" fields: %02Xx", screen_descriptor.fields);
WiredHome 177:d8e65c0e268a 551 INFO(" gct: %2d", (screen_descriptor.fields & 0x80) ? 1 : 0);
WiredHome 177:d8e65c0e268a 552 INFO(" res: %2d", ((screen_descriptor.fields & 0x70) >> 4) + 1);
WiredHome 177:d8e65c0e268a 553 INFO(" sort: %2d", (screen_descriptor.fields & 0x08) ? 1 : 0);
WiredHome 177:d8e65c0e268a 554 INFO(" gct siz: %2d", 1 << ((screen_descriptor.fields & 0x07) + 1));
WiredHome 177:d8e65c0e268a 555 INFO(" back clr: %d", screen_descriptor.background_color_index);
WiredHome 177:d8e65c0e268a 556 INFO(" pix rat: %d", screen_descriptor.pixel_aspect_ratio);
WiredHome 152:a013ac0133e4 557 return noerror;
WiredHome 152:a013ac0133e4 558 }
WiredHome 152:a013ac0133e4 559
WiredHome 152:a013ac0133e4 560
WiredHome 152:a013ac0133e4 561 RetCode_t GraphicsDisplay::GetGIFMetrics(gif_screen_descriptor_t * imageDescriptor, const char * Name_GIF) {
WiredHome 152:a013ac0133e4 562 RetCode_t ret = not_supported_format;
WiredHome 152:a013ac0133e4 563
WiredHome 152:a013ac0133e4 564 if (screen_descriptor_isvalid) {
WiredHome 152:a013ac0133e4 565 ret = noerror;
WiredHome 152:a013ac0133e4 566 } else {
WiredHome 152:a013ac0133e4 567 FILE *fh = fopen(Name_GIF, "rb");
WiredHome 152:a013ac0133e4 568 if (fh) {
WiredHome 152:a013ac0133e4 569 ret = GetGIFHeader(fh);
WiredHome 152:a013ac0133e4 570 fclose(fh);
WiredHome 152:a013ac0133e4 571 }
WiredHome 152:a013ac0133e4 572 }
WiredHome 152:a013ac0133e4 573 if (ret == noerror)
WiredHome 152:a013ac0133e4 574 *imageDescriptor = screen_descriptor;
WiredHome 152:a013ac0133e4 575 return ret;
WiredHome 152:a013ac0133e4 576 }
WiredHome 152:a013ac0133e4 577
WiredHome 152:a013ac0133e4 578
WiredHome 152:a013ac0133e4 579 RetCode_t GraphicsDisplay::RenderGIFFile(loc_t x, loc_t y, const char *Name_GIF) {
WiredHome 152:a013ac0133e4 580 RetCode_t rt = file_not_found;
WiredHome 152:a013ac0133e4 581
WiredHome 152:a013ac0133e4 582 INFO("Opening {%s}", Name_GIF);
WiredHome 152:a013ac0133e4 583 screen_descriptor_isvalid = false;
WiredHome 152:a013ac0133e4 584 FILE *fh = fopen(Name_GIF, "rb");
WiredHome 152:a013ac0133e4 585 if (fh) {
WiredHome 152:a013ac0133e4 586 if (hasGIFHeader(fh)) {
WiredHome 152:a013ac0133e4 587 rt = _RenderGIF(x, y, fh);
WiredHome 152:a013ac0133e4 588 }
WiredHome 152:a013ac0133e4 589 fclose(fh);
WiredHome 152:a013ac0133e4 590 if (global_color_table)
WiredHome 152:a013ac0133e4 591 free(global_color_table);
WiredHome 152:a013ac0133e4 592 if (local_color_table)
WiredHome 152:a013ac0133e4 593 free(local_color_table);
WiredHome 152:a013ac0133e4 594 }
WiredHome 152:a013ac0133e4 595 return rt;
WiredHome 152:a013ac0133e4 596 }
WiredHome 152:a013ac0133e4 597
WiredHome 152:a013ac0133e4 598