- [FIX] Windows no admet directoris que es diguen "aux", el molt membrillo
. [NEW] Compilació migrada a lagueirto
This commit is contained in:
227
source/other/gif.h
Normal file
227
source/other/gif.h
Normal file
@@ -0,0 +1,227 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define READ(dst, size) memcpy(dst, buffer, size); buffer += size
|
||||
|
||||
struct rgb { uint8_t r, g, b; };
|
||||
|
||||
struct image_descriptor_t
|
||||
{
|
||||
uint16_t left, top, width, height;
|
||||
uint8_t fields;
|
||||
};
|
||||
|
||||
struct dictionary_entry_t
|
||||
{
|
||||
unsigned char byte;
|
||||
int prev, len;
|
||||
};
|
||||
|
||||
void uncompress( int code_length, const uint8_t *input, int input_length, uint8_t *out )
|
||||
{
|
||||
dictionary_entry_t *dictionary;
|
||||
int dictionary_ind;
|
||||
|
||||
const int clear_code = 1 << ( code_length );
|
||||
const int stop_code = clear_code + 1;
|
||||
const int reset_code_length = code_length;
|
||||
|
||||
dictionary = ( dictionary_entry_t * )
|
||||
malloc( sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
|
||||
for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ )
|
||||
{
|
||||
dictionary[ dictionary_ind ].byte = dictionary_ind;
|
||||
dictionary[ dictionary_ind ].prev = -1;
|
||||
dictionary[ dictionary_ind ].len = 1;
|
||||
}
|
||||
dictionary_ind+=2;
|
||||
|
||||
int prev = -1;
|
||||
uint32_t mask = 0x01;
|
||||
while ( input_length )
|
||||
{
|
||||
int code = 0x0;
|
||||
|
||||
for (int i=0; i<(code_length + 1); i++)
|
||||
{
|
||||
const int bit = ( *input & mask ) ? 1 : 0;
|
||||
mask <<= 1;
|
||||
|
||||
if ( mask == 0x100 )
|
||||
{
|
||||
mask = 0x01;
|
||||
input++;
|
||||
input_length--;
|
||||
}
|
||||
|
||||
code = code | ( bit << i );
|
||||
}
|
||||
|
||||
if ( code == clear_code )
|
||||
{
|
||||
code_length = reset_code_length;
|
||||
dictionary = ( dictionary_entry_t * ) realloc( dictionary, sizeof( dictionary_entry_t ) * ( 1 << ( code_length + 1 ) ) );
|
||||
|
||||
for ( dictionary_ind = 0; dictionary_ind < ( 1 << code_length ); dictionary_ind++ )
|
||||
{
|
||||
dictionary[ dictionary_ind ].byte = dictionary_ind;
|
||||
dictionary[ dictionary_ind ].prev = -1;
|
||||
dictionary[ dictionary_ind ].len = 1;
|
||||
}
|
||||
dictionary_ind+=2;
|
||||
prev = -1;
|
||||
continue;
|
||||
}
|
||||
else if ( code == stop_code ) break;
|
||||
|
||||
if ( (prev > -1) && (code_length < 12) )
|
||||
{
|
||||
if (code > dictionary_ind)
|
||||
{
|
||||
fprintf( stderr, "code = %.02x, but dictionary_ind = %.02x\n", code, dictionary_ind );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
int ptr = (code == dictionary_ind) ? prev : code;
|
||||
while ( dictionary[ ptr ].prev != -1 ) ptr = dictionary[ ptr ].prev;
|
||||
dictionary[ dictionary_ind ].byte = dictionary[ ptr ].byte;
|
||||
|
||||
dictionary[ dictionary_ind ].prev = prev;
|
||||
dictionary[ dictionary_ind ].len = dictionary[ prev ].len + 1;
|
||||
dictionary_ind++;
|
||||
|
||||
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 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
prev = code;
|
||||
|
||||
const int match_len = dictionary[ code ].len;
|
||||
while ( code != -1 )
|
||||
{
|
||||
out[ dictionary[ code ].len - 1 ] = dictionary[ code ].byte;
|
||||
if ( dictionary[ code ].prev == code )
|
||||
{
|
||||
fprintf( stderr, "Internal error; self-reference." );
|
||||
exit( 0 );
|
||||
}
|
||||
code = dictionary[ code ].prev;
|
||||
}
|
||||
out += match_len;
|
||||
}
|
||||
}
|
||||
|
||||
static int read_sub_blocks( uint8_t* buffer, uint8_t **data )
|
||||
{
|
||||
int data_length = 0;
|
||||
*data = NULL;
|
||||
int index = 0;
|
||||
|
||||
while (1) {
|
||||
uint8_t block_size = *(buffer++);
|
||||
if ( block_size == 0 ) break;
|
||||
|
||||
data_length += block_size;
|
||||
*data = (uint8_t*)realloc( *data, data_length );
|
||||
READ(*data + index, block_size);
|
||||
index += block_size;
|
||||
}
|
||||
|
||||
return data_length;
|
||||
}
|
||||
|
||||
uint8_t* process_image_descriptor( uint8_t* buffer, rgb *gct, int gct_size, int resolution_bits )
|
||||
{
|
||||
image_descriptor_t image_descriptor;
|
||||
READ(&image_descriptor, 9);
|
||||
|
||||
uint8_t lzw_code_size;
|
||||
READ(&lzw_code_size, 1);
|
||||
|
||||
uint8_t *compressed_data = NULL;
|
||||
const int compressed_data_length = read_sub_blocks( buffer, &compressed_data );
|
||||
|
||||
const int uncompressed_data_length = image_descriptor.width * image_descriptor.height;
|
||||
uint8_t *uncompressed_data = (uint8_t*)malloc( uncompressed_data_length );
|
||||
|
||||
uncompress( lzw_code_size, compressed_data, compressed_data_length, uncompressed_data );
|
||||
|
||||
if ( compressed_data ) free( compressed_data );
|
||||
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
uint32_t* LoadPalette(uint8_t *buffer, uint16_t *size = NULL )
|
||||
{
|
||||
buffer += 10;
|
||||
const uint8_t fields = *buffer;
|
||||
|
||||
uint32_t *global_color_table = (uint32_t *)calloc(1, 1024);;
|
||||
|
||||
if (size) *size = 0;
|
||||
if (fields & 0x80) {
|
||||
int global_color_table_size = 1 << (((fields & 0x07) + 1));
|
||||
if (size) *size = global_color_table_size;
|
||||
|
||||
for (int i=0; i<global_color_table_size;++i) {
|
||||
buffer+=3;
|
||||
global_color_table[i] = (buffer[0]<<16) + (buffer[1]<<8) + buffer[2];
|
||||
}
|
||||
}
|
||||
return global_color_table;
|
||||
}
|
||||
|
||||
static uint8_t* LoadGif(uint8_t *buffer, uint16_t* w, uint16_t* h)
|
||||
{
|
||||
int global_color_table_size = 0; // number of entries in global_color_table
|
||||
rgb *global_color_table = NULL;
|
||||
|
||||
buffer += 6; // Ignore header
|
||||
*w = *((uint16_t*)buffer); buffer+=2;
|
||||
*h = *((uint16_t*)buffer); buffer+=2;
|
||||
const uint8_t fields = *buffer; buffer+=3;
|
||||
|
||||
const int color_resolution_bits = ( ( fields & 0x70 ) >> 4 ) + 1;
|
||||
|
||||
if ( fields & 0x80 )
|
||||
{
|
||||
global_color_table_size = 1 << ( ( ( fields & 0x07 ) + 1 ) );
|
||||
global_color_table = (rgb*)malloc( 3 * global_color_table_size );
|
||||
READ(global_color_table, 3 * global_color_table_size);
|
||||
}
|
||||
|
||||
uint8_t block_type = 0x0;
|
||||
while ( block_type != 0x3B )
|
||||
{
|
||||
READ(&block_type, 1);
|
||||
|
||||
uint8_t size;
|
||||
switch ( block_type )
|
||||
{
|
||||
case 0x2C:
|
||||
return process_image_descriptor(buffer, global_color_table, global_color_table_size, color_resolution_bits);
|
||||
case 0x21:
|
||||
buffer++; //size = *(buffer++); buffer += size;
|
||||
do { size = *(buffer++); buffer += size; } while (size != 0);
|
||||
break;
|
||||
case 0x3B:
|
||||
break;
|
||||
default:
|
||||
fprintf( stderr, "Bailing on unrecognized block type %.02x\n", block_type );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*unsigned char* LoadGif(unsigned char *buffer, unsigned short* w, unsigned short* h) {
|
||||
return process_gif_stream(buffer, w, h);
|
||||
}*/
|
||||
174
source/other/gifenc.h
Normal file
174
source/other/gifenc.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DICT_SIZE 4096
|
||||
|
||||
namespace gif
|
||||
{
|
||||
typedef struct {
|
||||
int prefix;
|
||||
uint8_t character;
|
||||
} DictEntry;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
int bit_pos;
|
||||
uint32_t bit_buffer;
|
||||
} BitStream;
|
||||
|
||||
void bitstream_init(BitStream *bs) {
|
||||
bs->capacity = 256;
|
||||
bs->size = 0;
|
||||
bs->data = (uint8_t*)malloc(bs->capacity);
|
||||
bs->bit_pos = 0;
|
||||
bs->bit_buffer = 0;
|
||||
}
|
||||
|
||||
void bitstream_write(BitStream *bs, uint16_t code, int code_size) {
|
||||
bs->bit_buffer |= ((uint32_t)code) << bs->bit_pos;
|
||||
bs->bit_pos += code_size;
|
||||
|
||||
while (bs->bit_pos >= 8) {
|
||||
if (bs->size >= bs->capacity) {
|
||||
bs->capacity *= 2;
|
||||
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
|
||||
}
|
||||
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
|
||||
bs->bit_buffer >>= 8;
|
||||
bs->bit_pos -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void bitstream_flush(BitStream *bs) {
|
||||
if (bs->bit_pos > 0) {
|
||||
if (bs->size >= bs->capacity) {
|
||||
bs->capacity *= 2;
|
||||
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
|
||||
}
|
||||
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *lzw_compress(uint8_t *input, int width, int height, int min_code_size, size_t *out_size) {
|
||||
int clear_code = 1 << min_code_size;
|
||||
int end_code = clear_code + 1;
|
||||
int next_code = end_code + 1;
|
||||
int code_size = min_code_size + 1;
|
||||
|
||||
DictEntry dict[MAX_DICT_SIZE];
|
||||
int dict_len = next_code;
|
||||
|
||||
BitStream bs;
|
||||
bitstream_init(&bs);
|
||||
bitstream_write(&bs, clear_code, code_size);
|
||||
|
||||
int prefix = input[0];
|
||||
for (int i = 1; i < width * height; i++) {
|
||||
uint8_t c = input[i];
|
||||
|
||||
// Search for prefix + c in dictionary
|
||||
int found = -1;
|
||||
for (int j = end_code + 1; j < dict_len; j++) {
|
||||
if (dict[j].prefix == prefix && dict[j].character == c) {
|
||||
found = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != -1) {
|
||||
prefix = found; // Extend prefix
|
||||
} else {
|
||||
bitstream_write(&bs, prefix, code_size); // Emit current prefix
|
||||
if (dict_len < MAX_DICT_SIZE) {
|
||||
if (dict_len == (1 << code_size) && code_size < 12) code_size++;
|
||||
dict[dict_len].prefix = prefix;
|
||||
dict[dict_len].character = c;
|
||||
dict_len++;
|
||||
} else {
|
||||
bitstream_write(&bs, clear_code, code_size);
|
||||
dict_len = end_code + 1;
|
||||
code_size = min_code_size + 1;
|
||||
}
|
||||
prefix = c; // Start new prefix
|
||||
}
|
||||
}
|
||||
|
||||
// Emit final prefix and end code
|
||||
bitstream_write(&bs, prefix, code_size);
|
||||
bitstream_write(&bs, end_code, code_size);
|
||||
bitstream_flush(&bs);
|
||||
|
||||
*out_size = bs.size;
|
||||
return bs.data;
|
||||
}
|
||||
|
||||
void write_gif(const char *filename, uint8_t *pixels, int width, int height, uint8_t *palette, int palette_size) {
|
||||
FILE *f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
perror("Failed to open file");
|
||||
return;
|
||||
}
|
||||
|
||||
// Header
|
||||
fwrite("GIF89a", 1, 6, f);
|
||||
|
||||
// Determine min_code_size from palette_size
|
||||
int palette_depth = 0;
|
||||
while ((1 << palette_depth) < palette_size) palette_depth++;
|
||||
const int min_code_size = palette_depth < 2 ? 2 : palette_depth; // GIF spec requires at least 2
|
||||
|
||||
printf("min_code_size: %i\n", palette_depth);
|
||||
|
||||
// Logical Screen Descriptor
|
||||
uint8_t packed_field = palette ? (0x80 | ((palette_depth - 1) << 4) | (palette_depth - 1)) : 0x00;
|
||||
uint8_t screen_desc[] = {
|
||||
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
|
||||
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
|
||||
packed_field, // GCT flag + color resolution + size
|
||||
0x00, // Background color index
|
||||
0x00 // Pixel aspect ratio
|
||||
};
|
||||
fwrite(screen_desc, 1, sizeof(screen_desc), f);
|
||||
|
||||
// Global Color Table (if provided)
|
||||
if (palette) {
|
||||
int gct_size = 1 << palette_depth;
|
||||
fwrite(palette, 1, gct_size * 3, f);
|
||||
}
|
||||
|
||||
// Image Descriptor
|
||||
uint8_t image_desc[] = {
|
||||
0x2C, 0, 0, 0, 0,
|
||||
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
|
||||
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
|
||||
0x00 // No local color table
|
||||
};
|
||||
fwrite(image_desc, 1, sizeof(image_desc), f);
|
||||
|
||||
// LZW-compressed image data
|
||||
fwrite(&min_code_size, 1, 1, f);
|
||||
|
||||
size_t compressed_size;
|
||||
uint8_t *compressed = lzw_compress(pixels, width, height, min_code_size, &compressed_size);
|
||||
|
||||
// Write as sub-blocks
|
||||
size_t offset = 0;
|
||||
while (offset < compressed_size) {
|
||||
uint8_t block_size = (compressed_size - offset > 255) ? 255 : (uint8_t)(compressed_size - offset);
|
||||
fwrite(&block_size, 1, 1, f);
|
||||
fwrite(compressed + offset, 1, block_size, f);
|
||||
offset += block_size;
|
||||
}
|
||||
fputc(0x00, f); // Block terminator
|
||||
|
||||
// Trailer
|
||||
fputc(0x3B, f);
|
||||
|
||||
free(compressed);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
27
source/other/log.h
Normal file
27
source/other/log.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
enum LogLevel { LOG_OK, LOG_FAIL, LOG_WARN, LOG_INFO, LOG_LUART, LOG_LUALD, LOG_VERBOSE, LOG_UNSALTED };
|
||||
|
||||
static inline void log_msg(enum LogLevel level, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
switch (level) {
|
||||
case LOG_OK: printf("[\033[1;32m OK \033[0m] "); break;
|
||||
case LOG_FAIL: printf("[\033[1;31mFAIL\033[0m] "); break;
|
||||
case LOG_WARN: printf("[\033[1;33mWARN\033[0m] "); break;
|
||||
case LOG_INFO: printf("[\033[1;34mINFO\033[0m] "); break;
|
||||
case LOG_LUART: printf("[\033[1;35mLUA RUNTIME ERROR\033[0m] "); break;
|
||||
case LOG_LUALD: printf("[\033[1;35mLUA LOADING ERROR\033[0m] "); break;
|
||||
case LOG_VERBOSE: printf(" - "); break;
|
||||
case LOG_UNSALTED: break;
|
||||
}
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
#else
|
||||
#define log_msg(...) ((void)0)
|
||||
#endif
|
||||
Reference in New Issue
Block a user