- Treballant en que els GIFs no donen pel cul
This commit is contained in:
334
gifenc.h
334
gifenc.h
@@ -3,226 +3,174 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#define MAX_DICT_SIZE 4096
|
||||||
|
|
||||||
namespace gif
|
namespace gif
|
||||||
{
|
{
|
||||||
struct gif_t {
|
typedef struct {
|
||||||
uint16_t w, h;
|
int prefix;
|
||||||
int depth;
|
uint8_t character;
|
||||||
int bgindex;
|
} DictEntry;
|
||||||
FILE *fd;
|
|
||||||
int offset;
|
|
||||||
int nframes;
|
|
||||||
uint8_t *frame, *back;
|
|
||||||
uint32_t partial;
|
|
||||||
uint8_t buffer[0xFF];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct node_t {
|
typedef struct {
|
||||||
uint16_t key;
|
uint8_t *data;
|
||||||
node_t *children[];
|
size_t size;
|
||||||
};
|
size_t capacity;
|
||||||
|
int bit_pos;
|
||||||
|
uint32_t bit_buffer;
|
||||||
|
} BitStream;
|
||||||
|
|
||||||
static node_t *new_node(uint16_t key, int degree)
|
void bitstream_init(BitStream *bs) {
|
||||||
{
|
bs->capacity = 256;
|
||||||
node_t *node = (node_t*)calloc(1, sizeof(*node) + degree * sizeof(node_t *));
|
bs->size = 0;
|
||||||
if (node) node->key = key;
|
bs->data = (uint8_t*)malloc(bs->capacity);
|
||||||
return node;
|
bs->bit_pos = 0;
|
||||||
|
bs->bit_buffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static node_t *new_trie(int degree, int *nkeys)
|
void bitstream_write(BitStream *bs, uint16_t code, int code_size) {
|
||||||
{
|
bs->bit_buffer |= ((uint32_t)code) << bs->bit_pos;
|
||||||
node_t *root = new_node(0, degree);
|
bs->bit_pos += code_size;
|
||||||
/* Create nodes for single pixels. */
|
|
||||||
for (*nkeys = 0; *nkeys < degree; (*nkeys)++) root->children[*nkeys] = new_node(*nkeys, degree);
|
|
||||||
*nkeys += 2; /* skip clear code and stop code */
|
|
||||||
return root;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void del_trie(node_t *root, int degree)
|
while (bs->bit_pos >= 8) {
|
||||||
{
|
if (bs->size >= bs->capacity) {
|
||||||
if (!root) return;
|
bs->capacity *= 2;
|
||||||
for (int i = 0; i < degree; i++) del_trie(root->children[i], degree);
|
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
|
||||||
free(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void put_loop(gif_t *gif, uint16_t loop);
|
|
||||||
|
|
||||||
gif_t *create(const char *fname, uint16_t width, uint16_t height, uint8_t *palette, uint8_t depth, int16_t bgindex, int loop)
|
|
||||||
{
|
|
||||||
gif_t *gif = (gif_t*)calloc(1, sizeof(*gif) + (bgindex < 0 ? 2 : 1)*width*height);
|
|
||||||
gif->w = width; gif->h = height;
|
|
||||||
gif->bgindex = bgindex;
|
|
||||||
gif->frame = (uint8_t *) &gif[1];
|
|
||||||
gif->back = &gif->frame[width*height];
|
|
||||||
gif->fd = fopen(fname, "wb");
|
|
||||||
if (!gif->fd) { free(gif); return NULL; }
|
|
||||||
fwrite("GIF89a", 6, 1, gif->fd);
|
|
||||||
fwrite(&width, 2, 1, gif->fd);
|
|
||||||
fwrite(&height, 2, 1, gif->fd);
|
|
||||||
gif->depth = depth;
|
|
||||||
fputc((!palette?0x70:0xF0|(depth-1)), gif->fd);
|
|
||||||
fputc(bgindex, gif->fd); fputc(0, gif->fd);
|
|
||||||
if (palette) fwrite(palette, 3 << depth, 1, gif->fd);
|
|
||||||
if (loop >= 0 && loop <= 0xFFFF) put_loop(gif, (uint16_t)loop);
|
|
||||||
return gif;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void put_loop(gif_t *gif, uint16_t loop)
|
|
||||||
{
|
|
||||||
fputc('!', gif->fd); fputc(0xFF, gif->fd); fputc(0x0B, gif->fd);
|
|
||||||
fwrite("NETSCAPE2.0", 11, 1, gif->fd);
|
|
||||||
fputc(0x03, gif->fd); fputc(0x01, gif->fd);
|
|
||||||
fwrite(&loop, 2, 1, gif->fd);
|
|
||||||
fputc(0, gif->fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add packed key to buffer, updating offset and partial.
|
|
||||||
* gif->offset holds position to put next *bit*
|
|
||||||
* gif->partial holds bits to include in next byte */
|
|
||||||
static void put_key(gif_t *gif, uint16_t key, int key_size)
|
|
||||||
{
|
|
||||||
int byte_offset, bit_offset, bits_to_write;
|
|
||||||
byte_offset = gif->offset / 8;
|
|
||||||
bit_offset = gif->offset % 8;
|
|
||||||
gif->partial |= ((uint32_t) key) << bit_offset;
|
|
||||||
bits_to_write = bit_offset + key_size;
|
|
||||||
while (bits_to_write >= 8) {
|
|
||||||
gif->buffer[byte_offset++] = gif->partial & 0xFF;
|
|
||||||
if (byte_offset == 0xFF) {
|
|
||||||
fputc(0xFF, gif->fd);
|
|
||||||
fwrite(gif->buffer, 0xFF, 1, gif->fd);
|
|
||||||
byte_offset = 0;
|
|
||||||
}
|
}
|
||||||
gif->partial >>= 8;
|
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
|
||||||
bits_to_write -= 8;
|
bs->bit_buffer >>= 8;
|
||||||
|
bs->bit_pos -= 8;
|
||||||
}
|
}
|
||||||
gif->offset = (gif->offset + key_size) % (0xFF * 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_key(gif_t *gif)
|
void bitstream_flush(BitStream *bs) {
|
||||||
{
|
if (bs->bit_pos > 0) {
|
||||||
uint8_t byte_offset;
|
if (bs->size >= bs->capacity) {
|
||||||
byte_offset = gif->offset >> 3;
|
bs->capacity *= 2;
|
||||||
if (gif->offset & 0x07) gif->buffer[byte_offset++] = gif->partial & 0xFF;
|
bs->data = (uint8_t*)realloc(bs->data, bs->capacity);
|
||||||
if (byte_offset)
|
}
|
||||||
{
|
bs->data[bs->size++] = bs->bit_buffer & 0xFF;
|
||||||
fputc(byte_offset, gif->fd);
|
|
||||||
fwrite(gif->buffer, byte_offset, 1, gif->fd);
|
|
||||||
}
|
}
|
||||||
fputc(0, gif->fd);
|
|
||||||
gif->offset = gif->partial = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_image(gif_t *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y)
|
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 nkeys, key_size, i, j;
|
int end_code = clear_code + 1;
|
||||||
node_t *node, *child, *root;
|
int next_code = end_code + 1;
|
||||||
int degree = 1 << gif->depth;
|
int code_size = min_code_size + 1;
|
||||||
|
|
||||||
fputc(',', gif->fd);
|
DictEntry dict[MAX_DICT_SIZE];
|
||||||
fwrite(&x, 2, 1, gif->fd);
|
int dict_len = next_code;
|
||||||
fwrite(&y, 2, 1, gif->fd);
|
|
||||||
fwrite(&w, 2, 1, gif->fd);
|
BitStream bs;
|
||||||
fwrite(&h, 2, 1, gif->fd);
|
bitstream_init(&bs);
|
||||||
fputc(0, gif->fd); fputc(gif->depth, gif->fd);
|
bitstream_write(&bs, clear_code, code_size);
|
||||||
root = node = new_trie(degree, &nkeys);
|
|
||||||
key_size = gif->depth + 1;
|
int prefix = input[0];
|
||||||
put_key(gif, degree, key_size); /* clear code */
|
for (int i = 1; i < width * height; i++) {
|
||||||
for (i = y; i < y+h; i++) {
|
uint8_t c = input[i];
|
||||||
for (j = x; j < x+w; j++) {
|
|
||||||
uint8_t pixel = gif->frame[i*gif->w+j] & (degree - 1);
|
// Search for prefix + c in dictionary
|
||||||
child = node->children[pixel];
|
int found = -1;
|
||||||
if (child) {
|
for (int j = end_code + 1; j < dict_len; j++) {
|
||||||
node = child;
|
if (dict[j].prefix == prefix && dict[j].character == c) {
|
||||||
} else {
|
found = j;
|
||||||
put_key(gif, node->key, key_size);
|
break;
|
||||||
if (nkeys < 0x1000) {
|
}
|
||||||
if (nkeys == (1 << key_size))
|
}
|
||||||
key_size++;
|
|
||||||
node->children[pixel] = new_node(nkeys++, degree);
|
if (found != -1) {
|
||||||
} else {
|
prefix = found; // Extend prefix
|
||||||
put_key(gif, degree, key_size); /* clear code */
|
} else {
|
||||||
del_trie(root, degree);
|
bitstream_write(&bs, prefix, code_size); // Emit current prefix
|
||||||
root = node = new_trie(degree, &nkeys);
|
if (dict_len < MAX_DICT_SIZE) {
|
||||||
key_size = gif->depth + 1;
|
dict[dict_len].prefix = prefix;
|
||||||
|
dict[dict_len].character = c;
|
||||||
|
dict_len++;
|
||||||
|
if (dict_len == (1 << code_size) && code_size < 12) {
|
||||||
|
code_size++;
|
||||||
}
|
}
|
||||||
node = root->children[pixel];
|
} else {
|
||||||
|
bitstream_write(&bs, clear_code, code_size);
|
||||||
|
dict_len = end_code + 1;
|
||||||
|
code_size = min_code_size + 1;
|
||||||
}
|
}
|
||||||
|
prefix = c; // Start new prefix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
put_key(gif, node->key, key_size);
|
|
||||||
put_key(gif, degree + 1, key_size); /* stop code */
|
// Emit final prefix and end code
|
||||||
end_key(gif);
|
bitstream_write(&bs, prefix, code_size);
|
||||||
del_trie(root, degree);
|
bitstream_write(&bs, end_code, code_size);
|
||||||
|
bitstream_flush(&bs);
|
||||||
|
|
||||||
|
*out_size = bs.size;
|
||||||
|
return bs.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_bbox(gif_t *gif, uint16_t *w, uint16_t *h, uint16_t *x, uint16_t *y)
|
void write_gif(const char *filename, uint8_t *pixels, int width, int height, uint8_t *palette, int palette_size) {
|
||||||
{
|
FILE *f = fopen(filename, "wb");
|
||||||
int i, j, k;
|
if (!f) {
|
||||||
int left, right, top, bottom;
|
perror("Failed to open file");
|
||||||
uint8_t back;
|
return;
|
||||||
left = gif->w; right = 0;
|
|
||||||
top = gif->h; bottom = 0;
|
|
||||||
k = 0;
|
|
||||||
for (i = 0; i < gif->h; i++) {
|
|
||||||
for (j = 0; j < gif->w; j++, k++) {
|
|
||||||
back = gif->bgindex >= 0 ? gif->bgindex : gif->back[k];
|
|
||||||
if (gif->frame[k] != back) {
|
|
||||||
if (j < left) left = j;
|
|
||||||
if (j > right) right = j;
|
|
||||||
if (i < top) top = i;
|
|
||||||
if (i > bottom) bottom = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (left != gif->w && top != gif->h) {
|
|
||||||
*x = left; *y = top;
|
// Header
|
||||||
*w = right - left + 1;
|
fwrite("GIF89a", 1, 6, f);
|
||||||
*h = bottom - top + 1;
|
|
||||||
return 1;
|
// Determine min_code_size from palette_size
|
||||||
} else {
|
int palette_depth = 0;
|
||||||
return 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);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void add_graphics_control_extension(gif_t *gif, uint16_t d)
|
// Image Descriptor
|
||||||
{
|
uint8_t image_desc[] = {
|
||||||
uint8_t flags = ((gif->bgindex >= 0 ? 2 : 1) << 2) + 1;
|
0x2C, 0, 0, 0, 0,
|
||||||
fputc('!', gif->fd); fputc(0xF9, gif->fd); fputc(0x04, gif->fd); fputc(flags, gif->fd);
|
uint8_t(width & 0xFF), uint8_t((width >> 8) & 0xFF),
|
||||||
fwrite(&d, 2, 1, gif->fd);
|
uint8_t(height & 0xFF), uint8_t((height >> 8) & 0xFF),
|
||||||
fputc(gif->bgindex, gif->fd); fputc(0, gif->fd);
|
0x00 // No local color table
|
||||||
}
|
};
|
||||||
|
fwrite(image_desc, 1, sizeof(image_desc), f);
|
||||||
|
|
||||||
void addFrame(gif_t *gif, uint16_t delay)
|
// LZW-compressed image data
|
||||||
{
|
fwrite(&min_code_size, 1, 1, f);
|
||||||
uint16_t w, h, x, y;
|
|
||||||
uint8_t *tmp;
|
|
||||||
|
|
||||||
if (delay || (gif->bgindex >= 0))
|
size_t compressed_size;
|
||||||
add_graphics_control_extension(gif, delay);
|
uint8_t *compressed = lzw_compress(pixels, width, height, min_code_size, &compressed_size);
|
||||||
if (gif->nframes == 0) {
|
|
||||||
w = gif->w;
|
// Write as sub-blocks
|
||||||
h = gif->h;
|
size_t offset = 0;
|
||||||
x = y = 0;
|
while (offset < compressed_size) {
|
||||||
} else if (!get_bbox(gif, &w, &h, &x, &y)) {
|
uint8_t block_size = (compressed_size - offset > 255) ? 255 : (uint8_t)(compressed_size - offset);
|
||||||
/* image's not changed; save one pixel just to add delay */
|
fwrite(&block_size, 1, 1, f);
|
||||||
w = h = 1;
|
fwrite(compressed + offset, 1, block_size, f);
|
||||||
x = y = 0;
|
offset += block_size;
|
||||||
}
|
}
|
||||||
put_image(gif, w, h, x, y);
|
fputc(0x00, f); // Block terminator
|
||||||
gif->nframes++;
|
|
||||||
if (gif->bgindex < 0) {
|
|
||||||
tmp = gif->back;
|
|
||||||
gif->back = gif->frame;
|
|
||||||
gif->frame = tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void close(gif_t* gif)
|
// Trailer
|
||||||
{
|
fputc(0x3B, f);
|
||||||
fputc(';', gif->fd);
|
|
||||||
fclose(gif->fd);
|
|
||||||
free(gif);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
free(compressed);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
228
gifenc_old.h
Normal file
228
gifenc_old.h
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
namespace gif
|
||||||
|
{
|
||||||
|
struct gif_t {
|
||||||
|
uint16_t w, h;
|
||||||
|
int depth;
|
||||||
|
int bgindex;
|
||||||
|
FILE *fd;
|
||||||
|
int offset;
|
||||||
|
int nframes;
|
||||||
|
uint8_t *frame, *back;
|
||||||
|
uint32_t partial;
|
||||||
|
uint8_t buffer[0xFF];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct node_t {
|
||||||
|
uint16_t key;
|
||||||
|
node_t *children[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static node_t *new_node(uint16_t key, int degree)
|
||||||
|
{
|
||||||
|
node_t *node = (node_t*)calloc(1, sizeof(*node) + degree * sizeof(node_t *));
|
||||||
|
if (node) node->key = key;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static node_t *new_trie(int degree, int *nkeys)
|
||||||
|
{
|
||||||
|
node_t *root = new_node(0, degree);
|
||||||
|
/* Create nodes for single pixels. */
|
||||||
|
for (*nkeys = 0; *nkeys < degree; (*nkeys)++) root->children[*nkeys] = new_node(*nkeys, degree);
|
||||||
|
*nkeys += 2; /* skip clear code and stop code */
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void del_trie(node_t *root, int degree)
|
||||||
|
{
|
||||||
|
if (!root) return;
|
||||||
|
for (int i = 0; i < degree; i++) del_trie(root->children[i], degree);
|
||||||
|
free(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_loop(gif_t *gif, uint16_t loop);
|
||||||
|
|
||||||
|
gif_t *create(const char *fname, uint16_t width, uint16_t height, uint8_t *palette, uint8_t depth, int16_t bgindex, int loop)
|
||||||
|
{
|
||||||
|
gif_t *gif = (gif_t*)calloc(1, sizeof(*gif) + (bgindex < 0 ? 2 : 1)*width*height);
|
||||||
|
gif->w = width; gif->h = height;
|
||||||
|
gif->bgindex = bgindex;
|
||||||
|
gif->frame = (uint8_t *) &gif[1];
|
||||||
|
gif->back = &gif->frame[width*height];
|
||||||
|
gif->fd = fopen(fname, "wb");
|
||||||
|
if (!gif->fd) { free(gif); return NULL; }
|
||||||
|
fwrite("GIF89a", 6, 1, gif->fd);
|
||||||
|
fwrite(&width, 2, 1, gif->fd);
|
||||||
|
fwrite(&height, 2, 1, gif->fd);
|
||||||
|
gif->depth = depth;
|
||||||
|
fputc((!palette?0x70:0xF0|(depth-1)), gif->fd);
|
||||||
|
fputc(bgindex, gif->fd); fputc(0, gif->fd);
|
||||||
|
if (palette) fwrite(palette, 3 << depth, 1, gif->fd);
|
||||||
|
if (loop >= 0 && loop <= 0xFFFF) put_loop(gif, (uint16_t)loop);
|
||||||
|
return gif;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_loop(gif_t *gif, uint16_t loop)
|
||||||
|
{
|
||||||
|
fputc('!', gif->fd); fputc(0xFF, gif->fd); fputc(0x0B, gif->fd);
|
||||||
|
fwrite("NETSCAPE2.0", 11, 1, gif->fd);
|
||||||
|
fputc(0x03, gif->fd); fputc(0x01, gif->fd);
|
||||||
|
fwrite(&loop, 2, 1, gif->fd);
|
||||||
|
fputc(0, gif->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add packed key to buffer, updating offset and partial.
|
||||||
|
* gif->offset holds position to put next *bit*
|
||||||
|
* gif->partial holds bits to include in next byte */
|
||||||
|
static void put_key(gif_t *gif, uint16_t key, int key_size)
|
||||||
|
{
|
||||||
|
int byte_offset, bit_offset, bits_to_write;
|
||||||
|
byte_offset = gif->offset / 8;
|
||||||
|
bit_offset = gif->offset % 8;
|
||||||
|
gif->partial |= ((uint32_t) key) << bit_offset;
|
||||||
|
bits_to_write = bit_offset + key_size;
|
||||||
|
while (bits_to_write >= 8) {
|
||||||
|
gif->buffer[byte_offset++] = gif->partial & 0xFF;
|
||||||
|
if (byte_offset == 0xFF) {
|
||||||
|
fputc(0xFF, gif->fd);
|
||||||
|
fwrite(gif->buffer, 0xFF, 1, gif->fd);
|
||||||
|
byte_offset = 0;
|
||||||
|
}
|
||||||
|
gif->partial >>= 8;
|
||||||
|
bits_to_write -= 8;
|
||||||
|
}
|
||||||
|
gif->offset = (gif->offset + key_size) % (0xFF * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_key(gif_t *gif)
|
||||||
|
{
|
||||||
|
uint8_t byte_offset;
|
||||||
|
byte_offset = gif->offset >> 3;
|
||||||
|
if (gif->offset & 0x07) gif->buffer[byte_offset++] = gif->partial & 0xFF;
|
||||||
|
if (byte_offset)
|
||||||
|
{
|
||||||
|
fputc(byte_offset, gif->fd);
|
||||||
|
fwrite(gif->buffer, byte_offset, 1, gif->fd);
|
||||||
|
}
|
||||||
|
fputc(0, gif->fd);
|
||||||
|
gif->offset = gif->partial = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void put_image(gif_t *gif, uint16_t w, uint16_t h, uint16_t x, uint16_t y)
|
||||||
|
{
|
||||||
|
int nkeys, key_size, i, j;
|
||||||
|
node_t *node, *child, *root;
|
||||||
|
int degree = 1 << gif->depth;
|
||||||
|
|
||||||
|
fputc(',', gif->fd);
|
||||||
|
fwrite(&x, 2, 1, gif->fd);
|
||||||
|
fwrite(&y, 2, 1, gif->fd);
|
||||||
|
fwrite(&w, 2, 1, gif->fd);
|
||||||
|
fwrite(&h, 2, 1, gif->fd);
|
||||||
|
fputc(0, gif->fd); fputc(gif->depth, gif->fd);
|
||||||
|
root = node = new_trie(degree, &nkeys);
|
||||||
|
key_size = gif->depth + 1;
|
||||||
|
put_key(gif, degree, key_size); /* clear code */
|
||||||
|
for (i = y; i < y+h; i++) {
|
||||||
|
for (j = x; j < x+w; j++) {
|
||||||
|
uint8_t pixel = gif->frame[i*gif->w+j] & (degree - 1);
|
||||||
|
child = node->children[pixel];
|
||||||
|
if (child) {
|
||||||
|
node = child;
|
||||||
|
} else {
|
||||||
|
put_key(gif, node->key, key_size);
|
||||||
|
if (nkeys < 0x1000) {
|
||||||
|
if (nkeys == (1 << key_size))
|
||||||
|
key_size++;
|
||||||
|
node->children[pixel] = new_node(nkeys++, degree);
|
||||||
|
} else {
|
||||||
|
put_key(gif, degree, key_size); /* clear code */
|
||||||
|
del_trie(root, degree);
|
||||||
|
root = node = new_trie(degree, &nkeys);
|
||||||
|
key_size = gif->depth + 1;
|
||||||
|
}
|
||||||
|
node = root->children[pixel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
put_key(gif, node->key, key_size);
|
||||||
|
put_key(gif, degree + 1, key_size); /* stop code */
|
||||||
|
end_key(gif);
|
||||||
|
del_trie(root, degree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_bbox(gif_t *gif, uint16_t *w, uint16_t *h, uint16_t *x, uint16_t *y)
|
||||||
|
{
|
||||||
|
int i, j, k;
|
||||||
|
int left, right, top, bottom;
|
||||||
|
uint8_t back;
|
||||||
|
left = gif->w; right = 0;
|
||||||
|
top = gif->h; bottom = 0;
|
||||||
|
k = 0;
|
||||||
|
for (i = 0; i < gif->h; i++) {
|
||||||
|
for (j = 0; j < gif->w; j++, k++) {
|
||||||
|
back = gif->bgindex >= 0 ? gif->bgindex : gif->back[k];
|
||||||
|
if (gif->frame[k] != back) {
|
||||||
|
if (j < left) left = j;
|
||||||
|
if (j > right) right = j;
|
||||||
|
if (i < top) top = i;
|
||||||
|
if (i > bottom) bottom = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (left != gif->w && top != gif->h) {
|
||||||
|
*x = left; *y = top;
|
||||||
|
*w = right - left + 1;
|
||||||
|
*h = bottom - top + 1;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_graphics_control_extension(gif_t *gif, uint16_t d)
|
||||||
|
{
|
||||||
|
uint8_t flags = ((gif->bgindex >= 0 ? 2 : 1) << 2) + 1;
|
||||||
|
fputc('!', gif->fd); fputc(0xF9, gif->fd); fputc(0x04, gif->fd); fputc(flags, gif->fd);
|
||||||
|
fwrite(&d, 2, 1, gif->fd);
|
||||||
|
fputc(gif->bgindex, gif->fd); fputc(0, gif->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFrame(gif_t *gif, uint16_t delay)
|
||||||
|
{
|
||||||
|
uint16_t w, h, x, y;
|
||||||
|
uint8_t *tmp;
|
||||||
|
|
||||||
|
if (delay || (gif->bgindex >= 0))
|
||||||
|
add_graphics_control_extension(gif, delay);
|
||||||
|
if (gif->nframes == 0) {
|
||||||
|
w = gif->w;
|
||||||
|
h = gif->h;
|
||||||
|
x = y = 0;
|
||||||
|
} else if (!get_bbox(gif, &w, &h, &x, &y)) {
|
||||||
|
/* image's not changed; save one pixel just to add delay */
|
||||||
|
w = h = 1;
|
||||||
|
x = y = 0;
|
||||||
|
}
|
||||||
|
put_image(gif, w, h, x, y);
|
||||||
|
gif->nframes++;
|
||||||
|
if (gif->bgindex < 0) {
|
||||||
|
tmp = gif->back;
|
||||||
|
gif->back = gif->frame;
|
||||||
|
gif->frame = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void close(gif_t* gif)
|
||||||
|
{
|
||||||
|
fputc(';', gif->fd);
|
||||||
|
fclose(gif->fd);
|
||||||
|
free(gif);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
2
lua.cpp
2
lua.cpp
@@ -48,7 +48,7 @@ extern "C" {
|
|||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
//pal[i-1] = (r<<16)+(g<<8)+b;
|
//pal[i-1] = (r<<16)+(g<<8)+b;
|
||||||
}
|
}
|
||||||
savesurf(surface, str, pal, len-1);
|
savesurf(surface, str, pal, len);
|
||||||
} else {
|
} else {
|
||||||
savesurf(surface, str, nullptr);
|
savesurf(surface, str, nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
6
mini.cpp
6
mini.cpp
@@ -242,12 +242,14 @@ uint8_t loadsurf(const char* filename) {
|
|||||||
|
|
||||||
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors)
|
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors)
|
||||||
{
|
{
|
||||||
uint8_t depth=0;
|
gif::write_gif(filename, surfaces[surface].p, surfaces[surface].w, surfaces[surface].h, pal, colors);
|
||||||
|
/*uint8_t depth=0;
|
||||||
do { colors = colors >> 1; depth++; } while (colors!=0);
|
do { colors = colors >> 1; depth++; } while (colors!=0);
|
||||||
|
printf("pal depth: %i\n", depth);
|
||||||
gif::gif_t *file = gif::create(filename, surfaces[surface].w, surfaces[surface].h, pal, (pal?depth:8), -1, -1);
|
gif::gif_t *file = gif::create(filename, surfaces[surface].w, surfaces[surface].h, pal, (pal?depth:8), -1, -1);
|
||||||
memcpy(file->frame, surfaces[surface].p, surfaces[surface].w*surfaces[surface].h);
|
memcpy(file->frame, surfaces[surface].p, surfaces[surface].w*surfaces[surface].h);
|
||||||
gif::addFrame(file, 0);
|
gif::addFrame(file, 0);
|
||||||
gif::close(file);
|
gif::close(file);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void freesurf(uint8_t surface) {
|
void freesurf(uint8_t surface) {
|
||||||
|
|||||||
Reference in New Issue
Block a user