diff --git a/source/gif.cpp b/source/gif.cpp index 2888833..8b16f05 100644 --- a/source/gif.cpp +++ b/source/gif.cpp @@ -1,63 +1,39 @@ #include "gif.h" -#include // Para NULL, fprintf, stderr -#include // Para malloc, realloc, exit, calloc, free +#include // Para NULL, fprintf, stderr +#include // Para malloc, realloc, exit, calloc, free -void uncompress(int code_length, - const unsigned char *input, - int input_length, - unsigned char *out) +void Gif::uncompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) { - // int maxbits; int i, bit; int code, prev = -1; - dictionary_entry_t *dictionary; + std::vector dictionary; int dictionary_ind; unsigned int mask = 0x01; int reset_code_length; - int clear_code; // This varies depending on code_length - int stop_code; // one more than clear code + int clear_code; + int stop_code; int match_len; clear_code = 1 << (code_length); stop_code = clear_code + 1; - // To handle clear codes reset_code_length = code_length; - // Create a dictionary large enough to hold "code_length" entries. - // Once the dictionary overflows, code_length increases - dictionary = (dictionary_entry_t *) - malloc(sizeof(dictionary_entry_t) * (1 << (code_length + 1))); + dictionary.resize(1 << (code_length + 1)); - // Initialize the first 2^code_len entries of the dictionary with their - // indices. The rest of the entries will be built up dynamically. - - // Technically, it shouldn't be necessary to initialize the - // dictionary. The spec says that the encoder "should output a - // clear code as the first code in the image data stream". It doesn't - // say must, though... - for (dictionary_ind = 0; - dictionary_ind < (1 << code_length); - dictionary_ind++) + for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) { dictionary[dictionary_ind].byte = dictionary_ind; - // XXX this only works because prev is a 32-bit int (> 12 bits) dictionary[dictionary_ind].prev = -1; dictionary[dictionary_ind].len = 1; } - // 2^code_len + 1 is the special "end" code; don't give it an entry here - dictionary_ind++; - dictionary_ind++; + dictionary_ind += 2; - // TODO verify that the very last byte is clear_code + 1 while (input_length) { code = 0x0; - // Always read one more bit than the code length for (i = 0; i < (code_length + 1); i++) { - // This is different than in the file read example; that - // was a call to "next_bit" bit = (*input & mask) ? 1 : 0; mask <<= 1; @@ -74,49 +50,34 @@ void uncompress(int code_length, if (code == clear_code) { code_length = reset_code_length; - dictionary = (dictionary_entry_t *)realloc(dictionary, - sizeof(dictionary_entry_t) * (1 << (code_length + 1))); + dictionary.resize(1 << (code_length + 1)); - for (dictionary_ind = 0; - dictionary_ind < (1 << code_length); - dictionary_ind++) + for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) { dictionary[dictionary_ind].byte = dictionary_ind; - // XXX this only works because prev is a 32-bit int (> 12 bits) dictionary[dictionary_ind].prev = -1; dictionary[dictionary_ind].len = 1; } - dictionary_ind++; - dictionary_ind++; + dictionary_ind += 2; prev = -1; continue; } else if (code == stop_code) { - /*if ( input_length > 1 ) - { - fprintf( stderr, "Malformed GIF (early stop code)\n" ); - exit( 0 ); - }*/ break; } - // Update the dictionary with this character plus the _entry_ - // (character or string) that came before it if ((prev > -1) && (code_length < 12)) { if (code > dictionary_ind) { - fprintf(stderr, "code = %.02x, but dictionary_ind = %.02x\n", - code, dictionary_ind); + fprintf(stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind); exit(0); } - // Special handling for KwKwK if (code == dictionary_ind) { int ptr = prev; - while (dictionary[ptr].prev != -1) { ptr = dictionary[ptr].prev; @@ -134,25 +95,18 @@ void uncompress(int code_length, } dictionary[dictionary_ind].prev = prev; - dictionary[dictionary_ind].len = dictionary[prev].len + 1; - dictionary_ind++; - // GIF89a mandates that this stops at 12 bits - if ((dictionary_ind == (1 << (code_length + 1))) && - (code_length < 11)) + if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) { code_length++; - - dictionary = (dictionary_entry_t *)realloc(dictionary, - sizeof(dictionary_entry_t) * (1 << (code_length + 1))); + dictionary.resize(1 << (code_length + 1)); } } prev = code; - // Now copy the dictionary entry backwards into "out" match_len = dictionary[code].len; while (code != -1) { @@ -169,106 +123,75 @@ void uncompress(int code_length, } } -static int read_sub_blocks(unsigned char *buffer, unsigned char **data) +int Gif::read_sub_blocks(uint8_t *buffer, uint8_t **data) { - int data_length; - int index; - unsigned char block_size; + int data_length = 0; + int index = 0; + uint8_t block_size; - // Everything following are data sub-blocks, until a 0-sized block is - // encountered. - data_length = 0; - *data = NULL; - index = 0; + *data = nullptr; - while (1) + while (true) { READ(&block_size, 1); - if (block_size == 0) // end of sub-blocks + if (block_size == 0) { break; } data_length += block_size; - *data = (unsigned char *)realloc(*data, data_length); + *data = (uint8_t *)realloc(*data, data_length); - // TODO this could be split across block size boundaries READ(*data + index, block_size); - index += block_size; } return data_length; } -unsigned char *process_image_descriptor(unsigned char *buffer, - rgb *gct, - int gct_size, - int resolution_bits) +uint8_t *Gif::process_image_descriptor(uint8_t *buffer, RGB *gct, int gct_size, int resolution_bits) { - image_descriptor_t image_descriptor; + ImageDescriptor image_descriptor; int compressed_data_length; - unsigned char *compressed_data = NULL; - unsigned char lzw_code_size; + uint8_t *compressed_data = nullptr; + uint8_t lzw_code_size; int uncompressed_data_length = 0; - unsigned char *uncompressed_data = NULL; + uint8_t *uncompressed_data = nullptr; - // TODO there could actually be lots of these READ(&image_descriptor, 9); - - // TODO if LCT = true, read the LCT - READ(&lzw_code_size, 1); compressed_data_length = read_sub_blocks(buffer, &compressed_data); + uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height; + uncompressed_data = (uint8_t *)malloc(uncompressed_data_length); - // width = image_descriptor.image_width; - // height = image_descriptor.image_height; - uncompressed_data_length = image_descriptor.image_width * - image_descriptor.image_height; - uncompressed_data = (unsigned char *)malloc(uncompressed_data_length); - - uncompress(lzw_code_size, compressed_data, compressed_data_length, - uncompressed_data); + uncompress(lzw_code_size, compressed_data, compressed_data_length, uncompressed_data); if (compressed_data) + { free(compressed_data); - - // if ( uncompressed_data ) - // free( uncompressed_data ); + } return uncompressed_data; } -/** - * @param gif_file the file descriptor of a file containing a - * GIF-encoded file. This should point to the first byte in - * the file when invoked. - */ -#define rb (*(buffer++)) - -uint32_t *LoadPalette(unsigned char *buffer) +uint32_t *Gif::LoadPalette(uint8_t *buffer) { - unsigned char header[7]; - screen_descriptor_t screen_descriptor; - // int color_resolution_bits; - - int global_color_table_size = 0; // number of entries in global_color_table - uint32_t *global_color_table = NULL; + uint8_t header[7]; + ScreenDescriptor screen_descriptor; + int global_color_table_size = 0; + uint32_t *global_color_table = nullptr; READ(header, 6); READ(&screen_descriptor, 7); - // color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; global_color_table = (uint32_t *)calloc(1, 1024); if (screen_descriptor.fields & 0x80) { global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); - // global_color_table = (rgb *)malloc(3 * global_color_table_size); - // READ(global_color_table, 3 * global_color_table_size); for (int i = 0; i < global_color_table_size; ++i) { global_color_table[i] = (buffer[0] << 16) + (buffer[1] << 8) + buffer[2]; @@ -278,37 +201,18 @@ uint32_t *LoadPalette(unsigned char *buffer) return global_color_table; } -static unsigned char *process_gif_stream(unsigned char *buffer, unsigned short *w, unsigned short *h) +uint8_t *Gif::process_gif_stream(uint8_t *buffer, uint16_t *w, uint16_t *h) { - unsigned char header[7]; - screen_descriptor_t screen_descriptor; + uint8_t header[7]; + ScreenDescriptor screen_descriptor; int color_resolution_bits; + int global_color_table_size = 0; + RGB *global_color_table = nullptr; + uint8_t block_type = 0x0; - int global_color_table_size = 0; // number of entries in global_color_table - rgb *global_color_table = NULL; - - unsigned char block_type = 0x0; - - // A GIF file starts with a Header (section 17) READ(header, 6); header[6] = 0x0; - // XXX there's another format, GIF87a, that you may still find - // floating around. - /*if ( strcmp( "GIF89a", (char*)header ) ) - { - fprintf( stderr, - "Invalid GIF file (header is '%s', should be 'GIF89a')\n", - header ); - return NULL; - }*/ - - // Followed by a logical screen descriptor - // Note that this works because GIFs specify little-endian order; on a - // big-endian machine, the height & width would need to be reversed. - - // Can't use sizeof here since GCC does byte alignment; - // sizeof( screen_descriptor_t ) = 8! READ(&screen_descriptor, 7); *w = screen_descriptor.width; *h = screen_descriptor.height; @@ -317,13 +221,8 @@ static unsigned char *process_gif_stream(unsigned char *buffer, unsigned short * if (screen_descriptor.fields & 0x80) { - // int i; - // If bit 7 is set, the next block is a global color table; read it global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); - - global_color_table = (rgb *)malloc(3 * global_color_table_size); - - // XXX this could conceivably return a short count... + global_color_table = (RGB *)malloc(3 * global_color_table_size); READ(global_color_table, 3 * global_color_table_size); } @@ -331,15 +230,11 @@ static unsigned char *process_gif_stream(unsigned char *buffer, unsigned short * { READ(&block_type, 1); - unsigned char size; + uint8_t size; switch (block_type) { case IMAGE_DESCRIPTOR: - return process_image_descriptor(buffer, - global_color_table, - global_color_table_size, - color_resolution_bits); - break; + return process_image_descriptor(buffer, global_color_table, global_color_table_size, color_resolution_bits); case EXTENSION_INTRODUCER: buffer++; size = *(buffer++); @@ -349,47 +244,18 @@ static unsigned char *process_gif_stream(unsigned char *buffer, unsigned short * size = *(buffer++); buffer += size; } while (size != 0); - - /*if ( !process_extension( buffer ) ) - { - return NULL; - }*/ break; case TRAILER: break; default: - fprintf(stderr, "Bailing on unrecognized block type %.02x\n", - block_type); - return NULL; + fprintf(stderr, "Bailing on unrecognized block type %.02x\n", block_type); + return nullptr; } } - return NULL; + return nullptr; } -unsigned char *LoadGif(unsigned char *buffer, unsigned short *w, unsigned short *h) +uint8_t *Gif::LoadGif(uint8_t *buffer, uint16_t *w, uint16_t *h) { return process_gif_stream(buffer, w, h); -} - -/*int main( int argc, char *argv[] ) -{ - FILE* gif_file; - - if ( argc < 2 ) - { - fprintf( stderr, "Usage: %s \n", argv[ 0 ] ); - exit( 0 ); - } - - gif_file = fopen( argv[ 1 ], "rb" ); - - if ( gif_file == NULL ) - { - fprintf( stderr, "Unable to open file '%s'", argv[ 1 ] ); - perror( ": " ); - } - - process_gif_stream( gif_file ); - - fclose( gif_file ); -}*/ \ No newline at end of file +} \ No newline at end of file diff --git a/source/gif.h b/source/gif.h index 7c14a08..104c908 100644 --- a/source/gif.h +++ b/source/gif.h @@ -1,7 +1,8 @@ #pragma once -#include // Para uint32_t -#include // Para memcpy +#include // Para uint32_t +#include // Para memcpy +#include #define EXTENSION_INTRODUCER 0x21 #define IMAGE_DESCRIPTOR 0x2C @@ -15,62 +16,71 @@ memcpy(dst, buffer, size); \ buffer += size -typedef struct +struct ScreenDescriptor { - unsigned short width; - unsigned short height; - unsigned char fields; - unsigned char background_color_index; - unsigned char pixel_aspect_ratio; -} screen_descriptor_t; + uint16_t width; + uint16_t height; + uint8_t fields; + uint8_t background_color_index; + uint8_t pixel_aspect_ratio; +}; -typedef struct +struct RGB { - unsigned char r, g, b; -} rgb; + uint8_t r, g, b; +}; -typedef struct +struct ImageDescriptor { - unsigned short image_left_position; - unsigned short image_top_position; - unsigned short image_width; - unsigned short image_height; - unsigned char fields; -} image_descriptor_t; + uint16_t image_left_position; + uint16_t image_top_position; + uint16_t image_width; + uint16_t image_height; + uint8_t fields; +}; -typedef struct +struct DictionaryEntry { - unsigned char byte; + uint8_t byte; int prev; int len; -} dictionary_entry_t; +}; -typedef struct +struct Extension { - unsigned char extension_code; - unsigned char block_size; -} extension_t; + uint8_t extension_code; + uint8_t block_size; +}; -typedef struct +struct GraphicControlExtension { - unsigned char fields; - unsigned short delay_time; - unsigned char transparent_color_index; -} graphic_control_extension_t; + uint8_t fields; + uint16_t delay_time; + uint8_t transparent_color_index; +}; -typedef struct +struct ApplicationExtension { - unsigned char application_id[8]; - unsigned char version[3]; -} application_extension_t; + uint8_t application_id[8]; + uint8_t version[3]; +}; -typedef struct +struct PlaintextExtension { - unsigned short left, top, width, height; - unsigned char cell_width, cell_height; - unsigned char foreground_color, background_color; -} plaintext_extension_t; + uint16_t left, top, width, height; + uint8_t cell_width, cell_height; + uint8_t foreground_color, background_color; +}; -void uncompress(int code_length, const unsigned char *input, int input_length, unsigned char *out); -uint32_t *LoadPalette(unsigned char *buffer); -unsigned char *LoadGif(unsigned char *buffer, unsigned short *w, unsigned short *h); \ No newline at end of file +class Gif +{ +public: + void uncompress(int code_length, const uint8_t *input, int input_length, uint8_t *out); + uint32_t *LoadPalette(uint8_t *buffer); + uint8_t *LoadGif(uint8_t *buffer, uint16_t *w, uint16_t *h); + +private: + int read_sub_blocks(uint8_t *buffer, uint8_t **data); + uint8_t *process_image_descriptor(uint8_t *buffer, RGB *gct, int gct_size, int resolution_bits); + uint8_t *process_gif_stream(uint8_t *buffer, uint16_t *w, uint16_t *h); +}; \ No newline at end of file diff --git a/source/texture.cpp b/source/texture.cpp index 3d34254..34dfe5f 100644 --- a/source/texture.cpp +++ b/source/texture.cpp @@ -1,4 +1,3 @@ - #include "texture.h" #include // Para SDL_GetError #include // Para SDL_CreateRGBSurfaceWithFormatFrom @@ -276,9 +275,10 @@ std::shared_ptr Texture::loadSurface(const std::string &file_path) // Cerrar el archivo (automáticamente manejado por std::ifstream) file.close(); - // Llamar a la función LoadGif + // Crear un objeto Gif y llamar a la función LoadGif + Gif gif; Uint16 w, h; - Uint8 *rawPixels = LoadGif(buffer.data(), &w, &h); + Uint8 *rawPixels = gif.LoadGif(buffer.data(), &w, &h); if (!rawPixels) { return nullptr; @@ -348,7 +348,8 @@ std::vector Texture::loadPaletteFromFile(const std::string &file_path) throw std::runtime_error("Error al leer el fichero: " + getFileName(file_path)); } - const auto *PAL = LoadPalette(buffer.data()); + Gif gif; + const auto *PAL = gif.LoadPalette(buffer.data()); if (!PAL) { return palette; @@ -380,4 +381,4 @@ void Texture::setPalette(int palette) } // Obtiene el renderizador -SDL_Renderer *Texture::getRenderer(){ return renderer_;} \ No newline at end of file +SDL_Renderer *Texture::getRenderer() { return renderer_; } \ No newline at end of file