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:
Fri Aug 17 01:29:06 2018 +0000
Revision:
154:ad2450fc3dc3
Parent:
152:a013ac0133e4
Child:
177:d8e65c0e268a
Documentation updates for using resistive touch.

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 152:a013ac0133e4 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 152:a013ac0133e4 134 dictionary = (dictionary_entry_t *) malloc(sizeof(dictionary_entry_t) * (1 << (code_length + 1)));
WiredHome 152:a013ac0133e4 135 if (dictionary == NULL)
WiredHome 152:a013ac0133e4 136 return not_enough_ram;
WiredHome 152:a013ac0133e4 137 // Initialize the first 2^code_len entries of the dictionary with their
WiredHome 152:a013ac0133e4 138 // indices. The rest of the entries will be built up dynamically.
WiredHome 152:a013ac0133e4 139
WiredHome 152:a013ac0133e4 140 // Technically, it shouldn't be necessary to initialize the
WiredHome 152:a013ac0133e4 141 // dictionary. The spec says that the encoder "should output a
WiredHome 152:a013ac0133e4 142 // clear code as the first code in the image data stream". It doesn't
WiredHome 152:a013ac0133e4 143 // say must, though...
WiredHome 152:a013ac0133e4 144 for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
WiredHome 152:a013ac0133e4 145 dictionary[dictionary_ind].byte = (uint8_t) dictionary_ind;
WiredHome 152:a013ac0133e4 146 // XXX this only works because prev is a 32-bit int (> 12 bits)
WiredHome 152:a013ac0133e4 147 dictionary[dictionary_ind].prev = -1;
WiredHome 152:a013ac0133e4 148 dictionary[dictionary_ind].len = 1;
WiredHome 152:a013ac0133e4 149 }
WiredHome 152:a013ac0133e4 150 // 2^code_len + 1 is the special "end" code; don't give it an entry here
WiredHome 152:a013ac0133e4 151 dictionary_ind++;
WiredHome 152:a013ac0133e4 152 dictionary_ind++;
WiredHome 152:a013ac0133e4 153
WiredHome 152:a013ac0133e4 154 // TODO verify that the very last byte is clear_code + 1
WiredHome 152:a013ac0133e4 155 while (input_length) {
WiredHome 152:a013ac0133e4 156 code = 0x0;
WiredHome 152:a013ac0133e4 157 // Always read one more bit than the code length
WiredHome 152:a013ac0133e4 158 for (i = 0; i < (code_length + 1); i++) {
WiredHome 152:a013ac0133e4 159 // This is different than in the file read example; that
WiredHome 152:a013ac0133e4 160 // was a call to "next_bit"
WiredHome 152:a013ac0133e4 161 bit = (*input & mask) ? 1 : 0;
WiredHome 152:a013ac0133e4 162 mask <<= 1;
WiredHome 152:a013ac0133e4 163 if (mask == 0x100) {
WiredHome 152:a013ac0133e4 164 mask = 0x01;
WiredHome 152:a013ac0133e4 165 input++;
WiredHome 152:a013ac0133e4 166 input_length--;
WiredHome 152:a013ac0133e4 167 }
WiredHome 152:a013ac0133e4 168 code = code | (bit << i);
WiredHome 152:a013ac0133e4 169 }
WiredHome 152:a013ac0133e4 170 if (code == clear_code) {
WiredHome 152:a013ac0133e4 171 code_length = reset_code_length;
WiredHome 152:a013ac0133e4 172 dictionary = (dictionary_entry_t *) realloc(dictionary,
WiredHome 152:a013ac0133e4 173 sizeof(dictionary_entry_t) * (1 << (code_length + 1)));
WiredHome 152:a013ac0133e4 174 for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
WiredHome 152:a013ac0133e4 175 dictionary[dictionary_ind].byte = (uint8_t) dictionary_ind;
WiredHome 152:a013ac0133e4 176 // XXX this only works because prev is a 32-bit int (> 12 bits)
WiredHome 152:a013ac0133e4 177 dictionary[dictionary_ind].prev = -1;
WiredHome 152:a013ac0133e4 178 dictionary[dictionary_ind].len = 1;
WiredHome 152:a013ac0133e4 179 }
WiredHome 152:a013ac0133e4 180 dictionary_ind++;
WiredHome 152:a013ac0133e4 181 dictionary_ind++;
WiredHome 152:a013ac0133e4 182 prev = -1;
WiredHome 152:a013ac0133e4 183 continue;
WiredHome 152:a013ac0133e4 184 } else if (code == stop_code) {
WiredHome 152:a013ac0133e4 185 if (input_length > 1) {
WiredHome 152:a013ac0133e4 186 free(dictionary);
WiredHome 152:a013ac0133e4 187 return not_supported_format;
WiredHome 152:a013ac0133e4 188 }
WiredHome 152:a013ac0133e4 189 break;
WiredHome 152:a013ac0133e4 190 }
WiredHome 152:a013ac0133e4 191
WiredHome 152:a013ac0133e4 192 // Update the dictionary with this character plus the _entry_
WiredHome 152:a013ac0133e4 193 // (character or string) that came before it
WiredHome 152:a013ac0133e4 194 if ((prev > -1) && (code_length < 12)) {
WiredHome 152:a013ac0133e4 195 if (code > dictionary_ind) {
WiredHome 152:a013ac0133e4 196 //fprintf(stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind);
WiredHome 152:a013ac0133e4 197 free(dictionary);
WiredHome 152:a013ac0133e4 198 return not_supported_format;
WiredHome 152:a013ac0133e4 199 }
WiredHome 152:a013ac0133e4 200 if (code == dictionary_ind) {
WiredHome 152:a013ac0133e4 201 int ptr = prev;
WiredHome 152:a013ac0133e4 202
WiredHome 152:a013ac0133e4 203 while (dictionary[ptr].prev != -1) {
WiredHome 152:a013ac0133e4 204 ptr = dictionary[ptr].prev;
WiredHome 152:a013ac0133e4 205 }
WiredHome 152:a013ac0133e4 206 dictionary[dictionary_ind].byte = dictionary[ptr].byte;
WiredHome 152:a013ac0133e4 207 } else {
WiredHome 152:a013ac0133e4 208 int ptr = code;
WiredHome 152:a013ac0133e4 209 while (dictionary[ptr].prev != -1) {
WiredHome 152:a013ac0133e4 210 ptr = dictionary[ptr].prev;
WiredHome 152:a013ac0133e4 211 }
WiredHome 152:a013ac0133e4 212 dictionary[dictionary_ind].byte = dictionary[ptr].byte;
WiredHome 152:a013ac0133e4 213 }
WiredHome 152:a013ac0133e4 214 dictionary[dictionary_ind].prev = prev;
WiredHome 152:a013ac0133e4 215 dictionary[dictionary_ind].len = dictionary[prev].len + 1;
WiredHome 152:a013ac0133e4 216 dictionary_ind++;
WiredHome 152:a013ac0133e4 217 // GIF89a mandates that this stops at 12 bits
WiredHome 152:a013ac0133e4 218 if ((dictionary_ind == (1 << (code_length + 1))) &&
WiredHome 152:a013ac0133e4 219 (code_length < 11)) {
WiredHome 152:a013ac0133e4 220 code_length++;
WiredHome 152:a013ac0133e4 221 dictionary = (dictionary_entry_t *) realloc(dictionary,
WiredHome 152:a013ac0133e4 222 sizeof(dictionary_entry_t) * (1 << (code_length + 1)));
WiredHome 152:a013ac0133e4 223 }
WiredHome 152:a013ac0133e4 224 }
WiredHome 152:a013ac0133e4 225 prev = code;
WiredHome 152:a013ac0133e4 226 // Now copy the dictionary entry backwards into "out"
WiredHome 152:a013ac0133e4 227 match_len = dictionary[code].len;
WiredHome 152:a013ac0133e4 228 while (code != -1) {
WiredHome 152:a013ac0133e4 229 int pos = dictionary[code].len - 1;
WiredHome 152:a013ac0133e4 230 out[pos] = dictionary[code].byte;
WiredHome 152:a013ac0133e4 231 //INFO("%p out[%d] = %02X\r\n", out, pos, out[pos]);
WiredHome 152:a013ac0133e4 232 if (dictionary[code].prev == code) {
WiredHome 152:a013ac0133e4 233 free(dictionary);
WiredHome 152:a013ac0133e4 234 return not_supported_format;
WiredHome 152:a013ac0133e4 235 }
WiredHome 152:a013ac0133e4 236 code = dictionary[code].prev;
WiredHome 152:a013ac0133e4 237 }
WiredHome 152:a013ac0133e4 238 out += match_len;
WiredHome 152:a013ac0133e4 239 }
WiredHome 152:a013ac0133e4 240 free(dictionary);
WiredHome 152:a013ac0133e4 241 return noerror;
WiredHome 152:a013ac0133e4 242 }
WiredHome 152:a013ac0133e4 243
WiredHome 152:a013ac0133e4 244
WiredHome 152:a013ac0133e4 245 /// read a block
WiredHome 152:a013ac0133e4 246 ///
WiredHome 152:a013ac0133e4 247 /// @param[in] fh is the handle to the gif file.
WiredHome 152:a013ac0133e4 248 /// @param[in] data is a pointer to a pointer to the data being processed.
WiredHome 152:a013ac0133e4 249 /// @return -1 on failure, 0 when done, or >0 as the length of a processed data block
WiredHome 152:a013ac0133e4 250 ///
WiredHome 152:a013ac0133e4 251 int GraphicsDisplay::read_gif_sub_blocks(FILE * fh, unsigned char **data) {
WiredHome 152:a013ac0133e4 252 int data_length;
WiredHome 152:a013ac0133e4 253 int index;
WiredHome 152:a013ac0133e4 254 unsigned char block_size;
WiredHome 152:a013ac0133e4 255
WiredHome 152:a013ac0133e4 256 // Everything following are data sub-blocks, until a 0-sized block is encountered.
WiredHome 152:a013ac0133e4 257 data_length = 0;
WiredHome 152:a013ac0133e4 258 *data = NULL;
WiredHome 152:a013ac0133e4 259 index = 0;
WiredHome 152:a013ac0133e4 260
WiredHome 152:a013ac0133e4 261 while (1) {
WiredHome 152:a013ac0133e4 262 if (read_filesystem_bytes(&block_size, 1, fh) < 1) {
WiredHome 152:a013ac0133e4 263 return -1;
WiredHome 152:a013ac0133e4 264 }
WiredHome 152:a013ac0133e4 265 if (block_size == 0) {
WiredHome 152:a013ac0133e4 266 break;
WiredHome 152:a013ac0133e4 267 }
WiredHome 152:a013ac0133e4 268 data_length += block_size;
WiredHome 152:a013ac0133e4 269 *data = (unsigned char *) realloc(*data, data_length);
WiredHome 152:a013ac0133e4 270 if (data) {
WiredHome 152:a013ac0133e4 271 if (read_filesystem_bytes(*data + index, block_size, fh) < block_size) {
WiredHome 152:a013ac0133e4 272 return -1;
WiredHome 152:a013ac0133e4 273 }
WiredHome 152:a013ac0133e4 274 index += block_size;
WiredHome 152:a013ac0133e4 275 } else {
WiredHome 152:a013ac0133e4 276 return -1;
WiredHome 152:a013ac0133e4 277 }
WiredHome 152:a013ac0133e4 278 }
WiredHome 152:a013ac0133e4 279 return data_length;
WiredHome 152:a013ac0133e4 280 }
WiredHome 152:a013ac0133e4 281
WiredHome 152:a013ac0133e4 282 // color table is encoded as 24-bit values, but we don't need that much space, since
WiredHome 152:a013ac0133e4 283 // the RA8875 is configured as either 8 or 16-bit color.
WiredHome 152:a013ac0133e4 284 //
WiredHome 152:a013ac0133e4 285 RetCode_t GraphicsDisplay::readColorTable(color_t * colorTable, int colorTableSize, FILE * fh) {
WiredHome 152:a013ac0133e4 286 struct {
WiredHome 152:a013ac0133e4 287 uint8_t r;
WiredHome 152:a013ac0133e4 288 uint8_t g;
WiredHome 152:a013ac0133e4 289 uint8_t b;
WiredHome 152:a013ac0133e4 290 } rgb;
WiredHome 152:a013ac0133e4 291 while (colorTableSize--) {
WiredHome 152:a013ac0133e4 292 if (read_filesystem_bytes(&rgb, 3, fh) < 3)
WiredHome 152:a013ac0133e4 293 return not_supported_format;
WiredHome 152:a013ac0133e4 294 *colorTable++ = RGB(rgb.r, rgb.g, rgb.b);
WiredHome 152:a013ac0133e4 295 }
WiredHome 152:a013ac0133e4 296 return noerror;
WiredHome 152:a013ac0133e4 297 }
WiredHome 152:a013ac0133e4 298
WiredHome 152:a013ac0133e4 299 RetCode_t GraphicsDisplay::readGIFImageDescriptor(FILE * fh, gif_image_descriptor_t * imageDescriptor) {
WiredHome 152:a013ac0133e4 300 if (read_filesystem_bytes(imageDescriptor, gif_image_descriptor_size, fh) < gif_image_descriptor_size)
WiredHome 152:a013ac0133e4 301 return not_supported_format;
WiredHome 152:a013ac0133e4 302 INFO("gif_image_descriptor\r\n");
WiredHome 152:a013ac0133e4 303 INFO(" left: %d\r\n", imageDescriptor->image_left_position);
WiredHome 152:a013ac0133e4 304 INFO(" top: %d\r\n", imageDescriptor->image_top_position);
WiredHome 152:a013ac0133e4 305 INFO(" width: %d\r\n", imageDescriptor->image_width);
WiredHome 152:a013ac0133e4 306 INFO(" height: %d\r\n", imageDescriptor->image_height);
WiredHome 152:a013ac0133e4 307 INFO(" fields: %02Xx\r\n", imageDescriptor->fields);
WiredHome 152:a013ac0133e4 308 INFO(" lct: %2d\r\n", (imageDescriptor->fields & 0x80) ? 1 : 0);
WiredHome 152:a013ac0133e4 309 INFO(" res: %2d\r\n", (imageDescriptor->fields & 0x40) ? 1 : 0);
WiredHome 152:a013ac0133e4 310 INFO(" sort: %2d\r\n", (imageDescriptor->fields & 0x20) ? 1 : 0);
WiredHome 152:a013ac0133e4 311 INFO(" res: %2d\r\n", ((imageDescriptor->fields & 0x18) >> 3));
WiredHome 152:a013ac0133e4 312 INFO(" lct siz: %2d\r\n", 1 << ((imageDescriptor->fields & 0x07) + 1));
WiredHome 152:a013ac0133e4 313 if (imageDescriptor->fields & 0x80) {
WiredHome 152:a013ac0133e4 314 local_color_table_size = 1 << ((imageDescriptor->fields & 0x07) + 1);
WiredHome 152:a013ac0133e4 315 local_color_table = (color_t *) malloc(sizeof(color_t) * local_color_table_size);
WiredHome 152:a013ac0133e4 316 if (local_color_table == NULL)
WiredHome 152:a013ac0133e4 317 return not_enough_ram;
WiredHome 152:a013ac0133e4 318 if (readColorTable(local_color_table, local_color_table_size, fh) != noerror) {
WiredHome 152:a013ac0133e4 319 free(local_color_table);
WiredHome 152:a013ac0133e4 320 local_color_table = NULL;
WiredHome 152:a013ac0133e4 321 return not_supported_format;
WiredHome 152:a013ac0133e4 322 }
WiredHome 152:a013ac0133e4 323 }
WiredHome 152:a013ac0133e4 324 return noerror;
WiredHome 152:a013ac0133e4 325 }
WiredHome 152:a013ac0133e4 326
WiredHome 152:a013ac0133e4 327 /// Process the image section of the GIF file
WiredHome 152:a013ac0133e4 328 ///
WiredHome 152:a013ac0133e4 329 /// @param[in] fh is the handle to the file.
WiredHome 152:a013ac0133e4 330 /// @param[in] uncompress_gifed_data is a pointer to a pointer to where the data will be placed.
WiredHome 152:a013ac0133e4 331 /// @returns true if all went well.
WiredHome 152:a013ac0133e4 332 ///
WiredHome 152:a013ac0133e4 333 RetCode_t GraphicsDisplay::process_gif_image_descriptor(FILE * fh, uint8_t ** uncompress_gifed_data, int width, int height) {
WiredHome 152:a013ac0133e4 334 int compressed_data_length;
WiredHome 152:a013ac0133e4 335 unsigned char *compressed_data = NULL;
WiredHome 152:a013ac0133e4 336 unsigned char lzw_code_size;
WiredHome 152:a013ac0133e4 337 int uncompress_gifed_data_length = 0;
WiredHome 152:a013ac0133e4 338 RetCode_t res = not_supported_format;
WiredHome 152:a013ac0133e4 339 local_color_table_size = 0;
WiredHome 152:a013ac0133e4 340
WiredHome 152:a013ac0133e4 341 if (read_filesystem_bytes(&lzw_code_size, 1, fh) < 1)
WiredHome 152:a013ac0133e4 342 goto done;
WiredHome 152:a013ac0133e4 343 INFO("lzw_code_size\r\n");
WiredHome 152:a013ac0133e4 344 INFO(" lzw code: %d\r\n", lzw_code_size);
WiredHome 152:a013ac0133e4 345 compressed_data_length = read_gif_sub_blocks(fh, &compressed_data);
WiredHome 152:a013ac0133e4 346 if (compressed_data_length > 0) {
WiredHome 152:a013ac0133e4 347 uncompress_gifed_data_length = width * height;
WiredHome 152:a013ac0133e4 348 *uncompress_gifed_data = (unsigned char *) malloc(uncompress_gifed_data_length);
WiredHome 152:a013ac0133e4 349 if (*uncompress_gifed_data == NULL)
WiredHome 152:a013ac0133e4 350 return not_enough_ram;
WiredHome 152:a013ac0133e4 351 res = uncompress_gif(lzw_code_size, compressed_data, compressed_data_length, *uncompress_gifed_data);
WiredHome 152:a013ac0133e4 352 }
WiredHome 152:a013ac0133e4 353 done:
WiredHome 152:a013ac0133e4 354 if (compressed_data)
WiredHome 152:a013ac0133e4 355 free(compressed_data);
WiredHome 152:a013ac0133e4 356 return res;
WiredHome 152:a013ac0133e4 357 }
WiredHome 152:a013ac0133e4 358
WiredHome 152:a013ac0133e4 359
WiredHome 152:a013ac0133e4 360 int GraphicsDisplay::process_gif_extension(FILE * fh) {
WiredHome 152:a013ac0133e4 361 extension_t extension;
WiredHome 152:a013ac0133e4 362 graphic_control_extension_t gce;
WiredHome 152:a013ac0133e4 363 application_extension_t application;
WiredHome 152:a013ac0133e4 364 plaintext_extension_t plaintext;
WiredHome 152:a013ac0133e4 365 unsigned char *extension_data = NULL;
WiredHome 152:a013ac0133e4 366 /* int extension_data_length; */
WiredHome 152:a013ac0133e4 367
WiredHome 152:a013ac0133e4 368 if (read_filesystem_bytes(&extension, extension_size, fh) < extension_size) {
WiredHome 152:a013ac0133e4 369 return 0;
WiredHome 152:a013ac0133e4 370 }
WiredHome 152:a013ac0133e4 371 INFO("extension\r\n");
WiredHome 152:a013ac0133e4 372 INFO(" code: %d\r\n", extension.extension_code);
WiredHome 152:a013ac0133e4 373 INFO(" block size: %d\r\n", extension.block_size);
WiredHome 152:a013ac0133e4 374 switch (extension.extension_code) {
WiredHome 152:a013ac0133e4 375 case GRAPHIC_CONTROL:
WiredHome 152:a013ac0133e4 376 if (read_filesystem_bytes(&gce, graphic_control_extension_size, fh) < graphic_control_extension_size) {
WiredHome 152:a013ac0133e4 377 return 0;
WiredHome 152:a013ac0133e4 378 }
WiredHome 152:a013ac0133e4 379 INFO("graphic_control_extension\r\n");
WiredHome 152:a013ac0133e4 380 INFO(" fields: %d\r\n", gce.fields);
WiredHome 152:a013ac0133e4 381 INFO(" delay time: %d\r\n", gce.delay_time);
WiredHome 152:a013ac0133e4 382 INFO(" transparent: %d\r\n", gce.transparent_color_index);
WiredHome 152:a013ac0133e4 383 break;
WiredHome 152:a013ac0133e4 384 case APPLICATION_EXTENSION:
WiredHome 152:a013ac0133e4 385 if (read_filesystem_bytes(&application, application_extension_size, fh) < application_extension_size) {
WiredHome 152:a013ac0133e4 386 return 0;
WiredHome 152:a013ac0133e4 387 }
WiredHome 152:a013ac0133e4 388 HexDump("application", (const uint8_t *) &application, sizeof(application));
WiredHome 152:a013ac0133e4 389 break;
WiredHome 152:a013ac0133e4 390 case COMMENT_EXTENSION:
WiredHome 152:a013ac0133e4 391 // comment extension; do nothing - all the data is in the
WiredHome 152:a013ac0133e4 392 // sub-blocks that follow.
WiredHome 152:a013ac0133e4 393 break;
WiredHome 152:a013ac0133e4 394 case PLAINTEXT_EXTENSION:
WiredHome 152:a013ac0133e4 395 if (read_filesystem_bytes(&plaintext, plaintext_extension_size, fh) < plaintext_extension_size) {
WiredHome 152:a013ac0133e4 396 return 0;
WiredHome 152:a013ac0133e4 397 }
WiredHome 152:a013ac0133e4 398 HexDump("plaintext", (const uint8_t *) &plaintext, sizeof(plaintext));
WiredHome 152:a013ac0133e4 399 break;
WiredHome 152:a013ac0133e4 400 default:
WiredHome 152:a013ac0133e4 401 return (0);
WiredHome 152:a013ac0133e4 402 }
WiredHome 152:a013ac0133e4 403 // All extensions are followed by data sub-blocks; even if it's
WiredHome 152:a013ac0133e4 404 // just a single data sub-block of length 0
WiredHome 152:a013ac0133e4 405 /* extension_data_length = */ read_gif_sub_blocks(fh, &extension_data);
WiredHome 152:a013ac0133e4 406 if (extension_data != NULL)
WiredHome 152:a013ac0133e4 407 free(extension_data);
WiredHome 152:a013ac0133e4 408 return 1;
WiredHome 152:a013ac0133e4 409 }
WiredHome 152:a013ac0133e4 410
WiredHome 152:a013ac0133e4 411
WiredHome 152:a013ac0133e4 412 RetCode_t GraphicsDisplay::_RenderGIF(loc_t ScreenX, loc_t ScreenY, FILE * fh) {
WiredHome 152:a013ac0133e4 413 //int color_resolution_bits;
WiredHome 152:a013ac0133e4 414 global_color_table_size = 0;
WiredHome 152:a013ac0133e4 415 local_color_table_size = 0;
WiredHome 152:a013ac0133e4 416
WiredHome 152:a013ac0133e4 417 if (GetGIFHeader(fh) != noerror)
WiredHome 152:a013ac0133e4 418 return not_supported_format;
WiredHome 152:a013ac0133e4 419 //color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
WiredHome 152:a013ac0133e4 420 if (screen_descriptor.fields & 0x80) {
WiredHome 152:a013ac0133e4 421 // If bit 7 is set, the next block is a global color table; read it
WiredHome 152:a013ac0133e4 422 global_color_table_size = 1 << ((screen_descriptor.fields & 0x07) + 1);
WiredHome 152:a013ac0133e4 423 global_color_table = (color_t *) malloc(sizeof(color_t) * global_color_table_size);
WiredHome 152:a013ac0133e4 424 if (global_color_table == NULL)
WiredHome 152:a013ac0133e4 425 return not_enough_ram;
WiredHome 152:a013ac0133e4 426 // XXX this could conceivably return a short count...
WiredHome 152:a013ac0133e4 427 if (readColorTable(global_color_table, global_color_table_size, fh) != noerror) {
WiredHome 152:a013ac0133e4 428 return not_supported_format;
WiredHome 152:a013ac0133e4 429 }
WiredHome 152:a013ac0133e4 430 HexDump("Global Color Table", (const uint8_t *) global_color_table, 3 * global_color_table_size);
WiredHome 152:a013ac0133e4 431 }
WiredHome 152:a013ac0133e4 432 unsigned char block_type = 0x0;
WiredHome 152:a013ac0133e4 433 uint8_t * uncompress_gifed_data = NULL;
WiredHome 152:a013ac0133e4 434 gif_image_descriptor_t gif_image_descriptor; // the image fragment
WiredHome 152:a013ac0133e4 435 while (block_type != TRAILER) {
WiredHome 152:a013ac0133e4 436 if (read_filesystem_bytes(&block_type, sizeof(block_type), fh) < sizeof(block_type))
WiredHome 152:a013ac0133e4 437 return not_supported_format;
WiredHome 152:a013ac0133e4 438 INFO("block type: %02X", block_type);
WiredHome 152:a013ac0133e4 439
WiredHome 152:a013ac0133e4 440 switch (block_type) {
WiredHome 152:a013ac0133e4 441 case IMAGE_DESCRIPTOR:
WiredHome 152:a013ac0133e4 442 if (readGIFImageDescriptor(fh, &gif_image_descriptor) != noerror)
WiredHome 152:a013ac0133e4 443 return not_supported_format;
WiredHome 152:a013ac0133e4 444 if (process_gif_image_descriptor(fh, &uncompress_gifed_data, gif_image_descriptor.image_width, gif_image_descriptor.image_height) == noerror) {
WiredHome 152:a013ac0133e4 445 if (uncompress_gifed_data) {
WiredHome 152:a013ac0133e4 446 // Ready to render to the screen
WiredHome 152:a013ac0133e4 447 INFO("Render to (%d,%d)\r\n", ScreenX, ScreenY);
WiredHome 152:a013ac0133e4 448 color_t * active_color_table = (local_color_table) ? local_color_table : global_color_table;
WiredHome 152:a013ac0133e4 449
WiredHome 152:a013ac0133e4 450 // create a local image buffer for this fragment
WiredHome 152:a013ac0133e4 451 color_t * cbmp = (color_t *) malloc(sizeof(color_t) * gif_image_descriptor.image_width * gif_image_descriptor.image_height);
WiredHome 152:a013ac0133e4 452 if (cbmp == NULL)
WiredHome 152:a013ac0133e4 453 return not_enough_ram;
WiredHome 152:a013ac0133e4 454 for (int i = 0; i < gif_image_descriptor.image_width * gif_image_descriptor.image_height; i++) {
WiredHome 152:a013ac0133e4 455 int cIndex = uncompress_gifed_data[i];
WiredHome 152:a013ac0133e4 456 cbmp[i] = active_color_table[cIndex];
WiredHome 152:a013ac0133e4 457 }
WiredHome 152:a013ac0133e4 458 // Write Fragment to Screen
WiredHome 152:a013ac0133e4 459 #if 0
WiredHome 152:a013ac0133e4 460 INFO("Render fragment: (%d,%d), offset: (%d,%d), w x h (%d,%d)\r\n",
WiredHome 152:a013ac0133e4 461 ScreenX, ScreenY,
WiredHome 152:a013ac0133e4 462 gif_image_descriptor.image_left_position,
WiredHome 152:a013ac0133e4 463 gif_image_descriptor.image_top_position,
WiredHome 152:a013ac0133e4 464 gif_image_descriptor.image_width,
WiredHome 152:a013ac0133e4 465 gif_image_descriptor.image_height);
WiredHome 152:a013ac0133e4 466 for (uint16_t y = 0; y < gif_image_descriptor.image_height; y++) {
WiredHome 152:a013ac0133e4 467 for (uint16_t x = 0; x < gif_image_descriptor.image_width; x++) {
WiredHome 152:a013ac0133e4 468 INFO("%04X ", cbmp[y * gif_image_descriptor.image_height + x]);
WiredHome 152:a013ac0133e4 469 }
WiredHome 152:a013ac0133e4 470 INFO("\r\n");
WiredHome 152:a013ac0133e4 471 }
WiredHome 152:a013ac0133e4 472 #else
WiredHome 152:a013ac0133e4 473 rect_t restore = windowrect;
WiredHome 152:a013ac0133e4 474 window(ScreenX + gif_image_descriptor.image_left_position,
WiredHome 152:a013ac0133e4 475 ScreenY + gif_image_descriptor.image_top_position,
WiredHome 152:a013ac0133e4 476 gif_image_descriptor.image_width,
WiredHome 152:a013ac0133e4 477 gif_image_descriptor.image_height);
WiredHome 152:a013ac0133e4 478 pixelStream(cbmp, screen_descriptor.width * screen_descriptor.height,
WiredHome 152:a013ac0133e4 479 ScreenX + gif_image_descriptor.image_left_position,
WiredHome 152:a013ac0133e4 480 ScreenY + gif_image_descriptor.image_top_position);
WiredHome 152:a013ac0133e4 481 window(restore);
WiredHome 152:a013ac0133e4 482 #endif
WiredHome 152:a013ac0133e4 483 // end write
WiredHome 152:a013ac0133e4 484 free(cbmp);
WiredHome 152:a013ac0133e4 485 }
WiredHome 152:a013ac0133e4 486 if (local_color_table) {
WiredHome 152:a013ac0133e4 487 free(local_color_table);
WiredHome 152:a013ac0133e4 488 local_color_table = NULL;
WiredHome 152:a013ac0133e4 489 }
WiredHome 152:a013ac0133e4 490 } else {
WiredHome 152:a013ac0133e4 491 return not_supported_format;
WiredHome 152:a013ac0133e4 492 }
WiredHome 152:a013ac0133e4 493 break;
WiredHome 152:a013ac0133e4 494 case EXTENSION_INTRODUCER:
WiredHome 152:a013ac0133e4 495 if (!process_gif_extension(fh))
WiredHome 152:a013ac0133e4 496 return not_supported_format;
WiredHome 152:a013ac0133e4 497 break;
WiredHome 152:a013ac0133e4 498 case TRAILER:
WiredHome 152:a013ac0133e4 499 break;
WiredHome 152:a013ac0133e4 500 default:
WiredHome 152:a013ac0133e4 501 return not_supported_format;
WiredHome 152:a013ac0133e4 502 }
WiredHome 152:a013ac0133e4 503 }
WiredHome 152:a013ac0133e4 504 return noerror;
WiredHome 152:a013ac0133e4 505 }
WiredHome 152:a013ac0133e4 506
WiredHome 152:a013ac0133e4 507
WiredHome 152:a013ac0133e4 508 // hasGIFHeader determines if it is a GIF file
WiredHome 152:a013ac0133e4 509 //
WiredHome 152:a013ac0133e4 510 // This reads a few bytes of the file and determines if they have the
WiredHome 152:a013ac0133e4 511 // GIF89a signature. GIF87a is not supported.
WiredHome 152:a013ac0133e4 512 //
WiredHome 152:a013ac0133e4 513 // @param fh is a file handle.
WiredHome 152:a013ac0133e4 514 // @returns true if it is GIF89a.
WiredHome 152:a013ac0133e4 515 //
WiredHome 152:a013ac0133e4 516 bool GraphicsDisplay::hasGIFHeader(FILE * fh) {
WiredHome 152:a013ac0133e4 517 char GIF_Header[6];
WiredHome 152:a013ac0133e4 518 if (read_filesystem_bytes(GIF_Header, sizeof(GIF_Header), fh) != sizeof(GIF_Header))
WiredHome 152:a013ac0133e4 519 return false;
WiredHome 152:a013ac0133e4 520 if (strncmp("GIF89a", GIF_Header, sizeof(GIF_Header)))
WiredHome 152:a013ac0133e4 521 return false;
WiredHome 152:a013ac0133e4 522 return true;
WiredHome 152:a013ac0133e4 523 }
WiredHome 152:a013ac0133e4 524
WiredHome 152:a013ac0133e4 525
WiredHome 152:a013ac0133e4 526 RetCode_t GraphicsDisplay::GetGIFHeader(FILE * fh) {
WiredHome 152:a013ac0133e4 527 if (read_filesystem_bytes(&screen_descriptor, gif_screen_descriptor_size, fh) < gif_screen_descriptor_size) {
WiredHome 152:a013ac0133e4 528 return not_supported_format;
WiredHome 152:a013ac0133e4 529 }
WiredHome 152:a013ac0133e4 530 screen_descriptor_isvalid = true;
WiredHome 152:a013ac0133e4 531 INFO("screen_descriptor\r\n");
WiredHome 152:a013ac0133e4 532 INFO(" width: %d\r\n", screen_descriptor.width);
WiredHome 152:a013ac0133e4 533 INFO(" height: %d\r\n", screen_descriptor.height);
WiredHome 152:a013ac0133e4 534 INFO(" fields: %02Xx\r\n", screen_descriptor.fields);
WiredHome 152:a013ac0133e4 535 INFO(" gct: %2d\r\n", (screen_descriptor.fields & 0x80) ? 1 : 0);
WiredHome 152:a013ac0133e4 536 INFO(" res: %2d\r\n", ((screen_descriptor.fields & 0x70) >> 4) + 1);
WiredHome 152:a013ac0133e4 537 INFO(" sort: %2d\r\n", (screen_descriptor.fields & 0x08) ? 1 : 0);
WiredHome 152:a013ac0133e4 538 INFO(" gct siz: %2d\r\n", 1 << ((screen_descriptor.fields & 0x07) + 1));
WiredHome 152:a013ac0133e4 539 INFO(" back clr: %d\r\n", screen_descriptor.background_color_index);
WiredHome 152:a013ac0133e4 540 INFO(" pix rat: %d\r\n", screen_descriptor.pixel_aspect_ratio);
WiredHome 152:a013ac0133e4 541 return noerror;
WiredHome 152:a013ac0133e4 542 }
WiredHome 152:a013ac0133e4 543
WiredHome 152:a013ac0133e4 544
WiredHome 152:a013ac0133e4 545 RetCode_t GraphicsDisplay::GetGIFMetrics(gif_screen_descriptor_t * imageDescriptor, const char * Name_GIF) {
WiredHome 152:a013ac0133e4 546 RetCode_t ret = not_supported_format;
WiredHome 152:a013ac0133e4 547
WiredHome 152:a013ac0133e4 548 if (screen_descriptor_isvalid) {
WiredHome 152:a013ac0133e4 549 ret = noerror;
WiredHome 152:a013ac0133e4 550 } else {
WiredHome 152:a013ac0133e4 551 FILE *fh = fopen(Name_GIF, "rb");
WiredHome 152:a013ac0133e4 552 if (fh) {
WiredHome 152:a013ac0133e4 553 ret = GetGIFHeader(fh);
WiredHome 152:a013ac0133e4 554 fclose(fh);
WiredHome 152:a013ac0133e4 555 }
WiredHome 152:a013ac0133e4 556 }
WiredHome 152:a013ac0133e4 557 if (ret == noerror)
WiredHome 152:a013ac0133e4 558 *imageDescriptor = screen_descriptor;
WiredHome 152:a013ac0133e4 559 return ret;
WiredHome 152:a013ac0133e4 560 }
WiredHome 152:a013ac0133e4 561
WiredHome 152:a013ac0133e4 562
WiredHome 152:a013ac0133e4 563 RetCode_t GraphicsDisplay::RenderGIFFile(loc_t x, loc_t y, const char *Name_GIF) {
WiredHome 152:a013ac0133e4 564 RetCode_t rt = file_not_found;
WiredHome 152:a013ac0133e4 565
WiredHome 152:a013ac0133e4 566 INFO("Opening {%s}", Name_GIF);
WiredHome 152:a013ac0133e4 567 screen_descriptor_isvalid = false;
WiredHome 152:a013ac0133e4 568 FILE *fh = fopen(Name_GIF, "rb");
WiredHome 152:a013ac0133e4 569 if (fh) {
WiredHome 152:a013ac0133e4 570 if (hasGIFHeader(fh)) {
WiredHome 152:a013ac0133e4 571 rt = _RenderGIF(x, y, fh);
WiredHome 152:a013ac0133e4 572 }
WiredHome 152:a013ac0133e4 573 fclose(fh);
WiredHome 152:a013ac0133e4 574 if (global_color_table)
WiredHome 152:a013ac0133e4 575 free(global_color_table);
WiredHome 152:a013ac0133e4 576 if (local_color_table)
WiredHome 152:a013ac0133e4 577 free(local_color_table);
WiredHome 152:a013ac0133e4 578 }
WiredHome 152:a013ac0133e4 579 return rt;
WiredHome 152:a013ac0133e4 580 }
WiredHome 152:a013ac0133e4 581
WiredHome 152:a013ac0133e4 582