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:
Tue Feb 11 21:26:59 2020 +0000
Revision:
196:56820026701b
Parent:
177:d8e65c0e268a
Child:
197:853d08e2fb53
Added puts w/point_t parameter.

Who changed what in which revision?

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