Library to control a Graphics TFT connected to 4-wire SPI - revised for the Raio RA8875 Display Controller.

Dependents:   FRDM_RA8875_mPaint RA8875_Demo RA8875_KeyPadDemo SignalGenerator ... more

Fork of SPI_TFT by Peter Drescher

See Components - RA8875 Based Display

Enhanced touch-screen support - where it previous supported both the Resistive Touch and Capacitive Touch based on the FT5206 Touch Controller, now it also has support for the GSL1680 Touch Controller.

Offline Help Manual (Windows chm)

/media/uploads/WiredHome/ra8875.zip.bin (download, rename to .zip and unzip)

Committer:
WiredHome
Date:
Thu Aug 08 11:29:48 2019 +0000
Revision:
183:808f272e481e
Parent:
177:d8e65c0e268a
Child:
196:56820026701b
Minor code-cleanup

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