Re: Animated screenshot and gif encoder...
- From: Thibault Duponchelle <t duponchelle gmail com>
- To: gtk-app-devel-list gnome org
- Subject: Re: Animated screenshot and gif encoder...
- Date: Fri, 29 Oct 2010 12:36:42 +0200
Hi !
Finally I have made a working code to create gif and add frame to it.
There's a lot of bugs currently (no time to correct it at the moment).
I give it to you as example if anybody is looking for something similar.
That's the code I've created to solve my problem :
void screenshot_anim_create_nostatic(GLOBAL_SKIN_INFOS* gsi) {
/* Magic number for Gif file format */
static char magic_number[] = {'G', 'I', 'F', '8', '9', 'a'};
/* Size of canvas width on 2 bytes, heigth on 2 bytes, GCT , bg color i
(place dans la palette ici c'est blanc) , aspect pixel ratio */
static char canvas[] = { 96, 0, 64, 0, 0x80, 0x0f, 0x00};
/* This header contains a lot of things : animation : NETSCAPE2.0. And a
comment */
static char header[31] = {
0x21, 0xff, 0x0b, 'N', 'E', 'T', 'S', 'C', 'A', 'P', 'E', '2', '.',
'0', 3, 1, 0, 0, 0,
0x21, 0xfe, 8, 'T', 'i', 'l', 'E', 'm', '2', 0, 0, 0 };
/* GCT, multiple de 2 */
static char palette[] = { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00};
/* Extension block introduced by 0x21 ('!'), and an img introduced by
0x2c (',') followed by coordinate corner(0,0), canvas 4 bytes, no local
color table */
static char sub_header[18] = {0x21, 0xf9, 4, 5, 11, 0, 0xff, 0, 0x2c, 0,
0, 0, 0, 96, 0, 64, 0, 0};
/* Get the pix into my appli */
int width, height;
guchar* lcddata;
int x, y;
width = gsi->emu->calc->hw.lcdwidth;
height = gsi->emu->calc->hw.lcdheight;
/* Alloc mmem */
lcddata = g_new(guchar, (width / 8) * height);
/* Get the lcd content using the function 's pointer from Benjamin's
core */
(*gsi->emu->calc->hw.get_lcd)(gsi->emu->calc, lcddata);
gsi->animation_file = fopen("gifencod.gif", "w");
fwrite(magic_number, 6, 1, gsi->animation_file);
fwrite(canvas, 7, 1, gsi->animation_file);
fwrite(header, 31, 1, gsi->animation_file);
fwrite(palette, 6, 1, gsi->animation_file);
fwrite(sub_header, 18, 1, gsi->animation_file);
long i= 0;
unsigned char q[(96*64)];
/* Ugly hack to convert to convert to black and white */
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
if (lcddata[(y * width + x) / 8] & (0x80 >> (x % 8))) {
//printf("i = %d", i);
q[i] = 0x01;
i++;
} else {
q[i] = 0x00;
i++;
}
}
}
/* Use external file based on whirlgif to encodei (LZW cryption) body of
gif */
GifEncode(gsi->animation_file, q , 1, (96*64));
}
/* Add a frame to an existing gif file */
void screenshot_anim_addframe(GLOBAL_SKIN_INFOS* gsi) {
/* Some specific thing from my appli */
int width, height;
guchar* lcddata;
int x, y;
long i= 0;
/* q will receive a modified copy of lcddata (lcddata comes from core
directly) */
unsigned char q[(96*64)];
width = gsi->emu->calc->hw.lcdwidth;
height = gsi->emu->calc->hw.lcdheight;
/* Alloc mmem */
lcddata = g_new(guchar, (width / 8) * height);
/* Get the lcd content using the function 's pointer from Benjamin's
core */
(*gsi->emu->calc->hw.get_lcd)(gsi->emu->calc, lcddata);
/* Extension block introduced by 0x21 ('!'), and an img introduced by
0x2c (',') followed by coordinate corner(0,0), canvas 4 bytes, no local
color table */
static char sub_header[18] = {0x21, 0xf9, 4, 5, 11, 0, 0x0f, 0, 0x2c, 0,
0, 0, 0, 96, 0, 64, 0, 0};
/* The end value */
char end[1] = { 0xC3};
fwrite(sub_header, 18, 1, gsi->animation_file);
/* Format it for my black and white palette */
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
if (lcddata[(y * width + x) / 8] & (0x80 >> (x % 8))) {
//printf("i = %d", i);
q[i] = 0x01;
i++;
} else {
q[i] = 0x00;
i++;
}
}
}
/* Use external file to encode (LZW cryption) body of gif */
GifEncode(gsi->animation_file, q , 1, (96*64));
/* Write block end */
fwrite(end, 1, 1,gsi->animation_file);
}
And here is the external file which was used ...
I finally use gifencod.c from Hans Dinsen-Hansen and Michael A. Mayer
(inspired by gifcode.c) :
/*
* gifencode.c
*
* Copyright (c) 1997,1998 by Hans Dinsen-Hansen
* The algorithms are inspired by those of gifcode.c
* Copyright (c) 1995,1996 Michael A. Mayer
* All rights reserved.
*
* This software may be freely copied, modified and redistributed
* without fee provided that above copyright notices are preserved
* intact on all copies and modified copies.
*
* There is no warranty or other guarantee of fitness of this software.
* It is provided solely "as is". The author(s) disclaim(s) all
* responsibility and liability with respect to this software's usage
* or its effect upon hardware or computer systems.
*
* The Graphics Interchange format (c) is the Copyright property of
* Compuserve Incorporated. Gif(sm) is a Service Mark property of
* Compuserve Incorporated.
*
*
* Implements GIF encoding by means of a tree search.
* --------------------------------------------------
*
* - The string table may be thought of being stored in a "b-tree of
* steroids," or more specifically, a {256,128,...,4}-tree, depending on
* the size of the color map.
* - Each (non-NULL) node contains the string table index (or code) and
* {256,128,...,4} pointers to other nodes.
* - For example, the index associated with the string 0-3-173-25 would be
* stored in:
* first->node[0]->node[3]->node[173]->node[25]->code
*
* - Speed and effectivity considerations, however, have made this
* implementation somewhat obscure, because it is costly to initialize
* a node-array where most elements will never be used.
* - Initially, a new node will be marked as terminating, TERMIN.
* If this node is used at a later stage, its mark will be changed.
* - Only nodes with several used nodes will be associated with a
* node-array. Such nodes are marked LOOKUP.
* - The remaining nodes are marked SEARCH. They are linked together
* in a search-list, where a field, NODE->alt, points at an alternative
* following color.
* - It is hardly feasible exactly to predict which nodes will have most
* used node pointers. The theory here is that the very first node as
* well as the first couple of nodes which need at least one alternative
* color, will be among the ones with many nodes ("... whatever that
* means", as my tutor in Num. Analysis and programming used to say).
* - The number of possible LOOKUP nodes depends on the size of the color
* map. Large color maps will have many SEARCH nodes; small color maps
* will probably have many LOOKUP nodes.
*/
#ifndef gif_encod_header
#include "gifencod.h"
#endif
#define BLOKLEN 255
#define BUFLEN 1000
int GifEncode(FILE *fout, unsigned char *pixels, int depth, int siz){
printf("1\n");
GifTree *first = &GifRoot, *newNode, *curNode;
UBYTE *end;
int cc, eoi, next, tel=0;
short cLength;
char *pos, *buffer;
empty[0] = NULL;
need = 8;
nodeArray = empty;
memmove(++nodeArray, empty, 255*sizeof(GifTree **));
if (( buffer = (char *)malloc((BUFLEN+1)*sizeof(char))) == NULL )
buffer++;
pos = buffer;
buffer[0] = 0x0;
cc = (depth == 1) ? 0x4 : 1<<depth;
fputc((depth == 1) ? 2 : depth, fout);
eoi = cc+1;
next = cc+2;
cLength = (depth == 1) ? 3 : depth+1;
printf("2\n");
if (( topNode = baseNode = (GifTree *)malloc(sizeof(GifTree)*4094)) ==
NULL )
return -1;
//TheEnd1("No memory for GIF-code tree");
if (( nodeArray = first->node = (GifTree **)malloc(256*sizeof(GifTree
*)*noOfArrays)) == NULL )
printf("error");
//TheEnd1("No memory for search nodes");
lastArray = nodeArray + ( 256*noOfArrays - cc);
ClearTree(cc, first);
pos = AddCodeToBuffer(cc, cLength, pos);
end = pixels+siz;
curNode = first;
while(pixels < end) {
if ( curNode->node[*pixels] != NULL ) {
curNode = curNode->node[*pixels];
tel++;
pixels++;
chainlen++;
continue;
} else if ( curNode->typ == SEARCH ) {
newNode = curNode->nxt;
while ( newNode->alt != NULL ) {
if ( newNode->ix == *pixels ) break;
newNode = newNode->alt;
}
if (newNode->ix == *pixels ) {
tel++;
pixels++;
chainlen++;
curNode = newNode;
continue;
}
}
/* ******************************************************
* If there is no more thread to follow, we create a new node. If the
* current node is terminating, it will become a SEARCH node. If it is
* a SEARCH node, and if we still have room, it will be converted to a
* LOOKUP node.
*/
newNode = ++topNode;
switch (curNode->typ ) {
case LOOKUP:
newNode->nxt = NULL;
newNode->alt = NULL,
curNode->node[*pixels] = newNode;
break;
case SEARCH:
if ( nodeArray != lastArray ) {
nodeArray += cc;
curNode->node = nodeArray;
curNode->typ = LOOKUP;
curNode->node[*pixels] = newNode;
curNode->node[(curNode->nxt)->ix] = curNode->nxt;
lookuptypes++;
newNode->nxt = NULL;
newNode->alt = NULL,
curNode->nxt = NULL;
break;
}
/* otherwise do as we do with a TERMIN node */
case TERMIN:
newNode->alt = curNode->nxt;
newNode->nxt = NULL,
curNode->nxt = newNode;
curNode->typ = SEARCH;
break;
default:
fprintf(stderr, "Silly node type: %d\n", curNode->typ);
}
newNode->code = next;
newNode->ix = *pixels;
newNode->typ = TERMIN;
newNode->node = empty;
nodecount++;
printf("4\n");
/*
* End of node creation
* ******************************************************
*/
if (debugFlag) {
if (curNode == newNode) fprintf(stderr, "Wrong choice of node\n");
if ( curNode->typ == LOOKUP && curNode->node[*pixels] != newNode )
fprintf(stderr, "Wrong pixel coding\n");
if ( curNode->typ == TERMIN ) fprintf(stderr, "Wrong Type coding; frame
no = %d; pixel# = %d; nodecount = %d\n", count, tel, nodecount);
}
pos = AddCodeToBuffer(curNode->code, cLength, pos);
if ( chainlen > maxchainlen ) maxchainlen = chainlen;
chainlen = 0;
if(pos-buffer>BLOKLEN) {
buffer[-1] = BLOKLEN;
fwrite(buffer-1, 1, BLOKLEN+1, fout);
buffer[0] = buffer[BLOKLEN];
buffer[1] = buffer[BLOKLEN+1];
buffer[2] = buffer[BLOKLEN+2];
buffer[3] = buffer[BLOKLEN+3];
pos -= BLOKLEN;
}
curNode = first;
if(next == (1<<cLength)) cLength++;
next++;
if(next == 0xfff) {
ClearTree(cc,first);
pos = AddCodeToBuffer(cc, cLength, pos);
if(pos-buffer>BLOKLEN) {
buffer[-1] = BLOKLEN;
fwrite(buffer-1, 1, BLOKLEN+1, fout);
buffer[0] = buffer[BLOKLEN];
buffer[1] = buffer[BLOKLEN+1];
buffer[2] = buffer[BLOKLEN+2];
buffer[3] = buffer[BLOKLEN+3];
pos -= BLOKLEN;
}
next = cc+2;
cLength = (depth == 1)?3:depth+1;
}
}
pos = AddCodeToBuffer(curNode->code, cLength, pos);
if(pos-buffer>BLOKLEN-3) {
buffer[-1] = BLOKLEN-3;
fwrite(buffer-1, 1, BLOKLEN-2, fout);
buffer[0] = buffer[BLOKLEN-3];
buffer[1] = buffer[BLOKLEN-2];
buffer[2] = buffer[BLOKLEN-1];
buffer[3] = buffer[BLOKLEN];
buffer[4] = buffer[BLOKLEN+1];
pos -= BLOKLEN-3;
}
pos = AddCodeToBuffer(eoi, cLength, pos);
pos = AddCodeToBuffer(0x0, -1, pos);
buffer[-1] = pos-buffer;
printf("5\n");
fwrite(buffer-1, pos-buffer+1, 1, fout);
//if((buffer -1) != NULL)
//free(buffer-1);
if((first->node) != NULL)
free(first->node);
if((baseNode) != NULL)
free(baseNode);
printf("6\n");
printf("7\n");
if (debugFlag) fprintf(stderr, "pixel count = %d; nodeCount = %d lookup
nodes = %d\n", tel, nodecount, lookuptypes);
return 0;
}
void ClearTree(int cc, GifTree *root)
{
int i;
GifTree *newNode, **xx;
if (debugFlag>1) fprintf(stderr, "Clear Tree cc= %d\n", cc);
if (debugFlag>1) fprintf(stderr, "nodeCount = %d lookup nodes = %d\n",
nodecount, lookuptypes);
maxchainlen=0; lookuptypes = 1;
nodecount = 0;
nodeArray = root->node;
xx= nodeArray;
for (i = 0; i < noOfArrays; i++ ) {
memmove (xx, empty, 256*sizeof(GifTree **));
xx += 256;
}
topNode = baseNode;
for(i=0; i<cc; i++) {
root->node[i] = newNode = ++topNode;
newNode->nxt = NULL;
newNode->alt = NULL;
newNode->code = i;
newNode->ix = i;
newNode->typ = TERMIN;
newNode->node = empty;
nodecount++;
}
}
char *AddCodeToBuffer(int code, short n, char *buf)
{
int mask;
if(n<0) {
if(need<8) {
buf++;
*buf = 0x0;
}
need = 8;
return buf;
}
while(n>=need) {
mask = (1<<need)-1;
*buf += (mask&code)<<(8-need);
buf++;
*buf = 0x0;
code = code>>need;
n -= need;
need = 8;
}
if(n) {
mask = (1<<n)-1;
*buf += (mask&code)<<(8-need);
need -= n;
}
return buf;
}
I hope this will be useful for someone :)
Best Regards.
Duponchelle Thibault
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]