Skip to content

Instantly share code, notes, and snippets.

@nabe-abk
Last active December 1, 2015 11:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nabe-abk/54ee2afb4c5b26d82dff to your computer and use it in GitHub Desktop.
Save nabe-abk/54ee2afb4c5b26d82dff to your computer and use it in GitHub Desktop.
GIF cat ( x86 only )
/*
* gifcat library
*
*[TAB=8], [EUC-JP]
*
* Copyright(C)2005 nabe@abk
* Last update : 2005/05/30
* ************************************************** *
* This program lisenced under MIT
* ************************************************** *
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>
#include "gifcat.h"
/*----------------------------------------------------------------------------
* initalize GIF image structure
*----------------------------------------------------------------------------*/
int init_gifimg(GIF_data *gif) {
if (!gif) return 1;
gif->header = 0;
gif->gctbl = 0;
gif->gctbl_size = 0;
gif->blks = 0;
return 0;
}
/*----------------------------------------------------------------------------
* Load GIF image file
*----------------------------------------------------------------------------*/
int load_gifimg(const char *fname, GIF_data *gif) {
int fd, fsize;
struct stat st;
int offset, offset_bak;
int blocks, magic, x;
unsigned char *buf;
GIF_header *gifh;
GIF_imgheader *imgh;
fd = open(fname, O_RDONLY);
if (fd == -1) return 1; // file open error
fstat(fd, &st); // file stat
if (st.st_size > GIF_MAX_SIZE) return 2; // too Large
// malloc and load
fsize = st.st_size;
buf = malloc(fsize);
gif->header = gifh = (GIF_header *)buf;
if (!buf) { close(fd); return 10; }
read(fd, buf, fsize);
close(fd);
if (gifh->signature[0] != 'G' || gifh->signature[1] != 'I' || gifh->signature[2] != 'F') return 20;
if (gifh->version[0] != '8' || gifh->version[2] != 'a') return 21;
if (gifh->version[1] != '7' && gifh->version[1] != '9') return 21;
offset = GIF_header_size;
gif->gctbl = (unsigned char *)0;
gif->gctbl_size = 0;
if (gifh->flags & 0x80) { // exist global color table
gif->gctbl = buf + offset;
gif->gctbl_size = (1 << ((gifh->flags & 7) +1))*3;
offset += gif->gctbl_size;
}
/* printf( "Load file : %s\n"
"Signature : %s\n"
"Version : %s\n"
"Size : %d x %d\n"
"flags : %02x\n"
"bg_index : %d\n"
"aspect : %d\n"
"g-colors : %d\n",
fname,
gifh->signature, gifh->version, gifh->width, gifh->height, gifh->flags, gifh->bg_index, gifh->aspect, 1 << ((gifh->flags & 7) +1)
); */
// block read loop
blocks = 0;
while(1) {
if (offset >= fsize) return 31;
offset_bak = offset;
magic = buf[offset]; // magic number
// printf("offset %x : magic %02x\n", offset, magic);
if (magic == 0x3b) break; // Trailer
if (magic == 0x2c) { // Load image block
imgh = (GIF_imgheader *)(buf + offset);
offset += GIF_imgheader_size;
if (imgh->flags & 0x80) { // exist local color table
gif->lctbl [blocks] = buf + offset;
gif->lctbl_size[blocks] = (1 << ((imgh->flags & 7) +1))*3;
offset += gif->lctbl_size[blocks];
} else {
gif->lctbl [blocks] = (unsigned char *)0;
gif->lctbl_size[blocks] = 0;
}
offset++; // LZW Minimum Code Size data
// block step loop
while((x = buf[offset++])) {
offset += x;
if (offset >= fsize) return 32;
}
gif->blk_header[blocks] = imgh;
gif->blk_size [blocks] = offset - offset_bak - gif->lctbl_size[blocks];
gif->step_left [blocks] = 0;
blocks++;
} else if (magic == 0x21) {
offset += 2; // step Introducer and Label
// block step loop
while((x = buf[offset++])) {
offset += x;
if (offset >= fsize) return 32;
}
} else {
return 39;
}
}
gif->blks = blocks;
return 0;
}
/*----------------------------------------------------------------------------
* Copy GIF Header
*----------------------------------------------------------------------------*/
int copy_GIF_header(GIF_data *gif0, GIF_data *gif1)
{
GIF_header *gifh0;
if (!gif0 || !gif1) return -1;
gif0->header = gifh0 = (GIF_header *)malloc(sizeof(GIF_header));
// copy Header
memcpy(gifh0, gif1->header, GIF_header_size);
gifh0->width = 0;
gif0->gctbl = gif1->gctbl;
gif0->gctbl_size = gif1->gctbl_size;
gif0->blks = 0;
return 0;
}
/*----------------------------------------------------------------------------
* Cat GIF image
*----------------------------------------------------------------------------*/
int catgif_right(GIF_data *gif0, GIF_data *gif1)
{
unsigned int i, blocks;
unsigned int width, flags;
unsigned int gctbl_is_identical;
unsigned int gctbl0_size, gctbl1_size;
unsigned char *gctbl0, *gctbl1;
GIF_header *gifh0, *gifh1;
if (!gif0 || !gif1) return -1;
gifh0 = gif0->header;
gifh1 = gif1->header;
if (gifh0->height != gifh1->height) { return 1; }
// load Global Color Tables infomation
gctbl0 = gif0->gctbl;
gctbl0_size = gif0->gctbl_size;
gctbl1 = gif1->gctbl;
gctbl1_size = gif1->gctbl_size;
gctbl_is_identical = 0;
if (gctbl0 == gctbl1 ||
(gctbl0_size == gctbl1_size && !memcmp(gctbl0, gctbl1, gctbl0_size)) )
gctbl_is_identical = 1;
// copy image blocks
blocks = gif0->blks;
width = gifh0->width;
for(i=0; i<(gif1->blks); i++) {
if (blocks >= GIF_MAX_BLOCKS) break;
gif0->blk_header[blocks] = gif1->blk_header[i];
gif0->blk_size [blocks] = gif1->blk_size [i];
gif0->step_left [blocks] = width;
// check palette
if (gif1->lctbl_size[i]) { // exist Local Color Table
gif0->lctbl [blocks] = gif1->lctbl [i];
gif0->lctbl_size[blocks] = gif1->lctbl_size[i];
} else if (gctbl_is_identical) { // global color table is identical
gif0->lctbl [blocks] = 0;
gif0->lctbl_size[blocks] = 0;
} else { // Create Local Color Table from global color table
gif0->lctbl [blocks] = gif1->lctbl [i] = gctbl1;
gif0->lctbl_size[blocks] = gif1->lctbl_size[i] = gctbl1_size;
flags = gif1->blk_header[i]->flags & 0x78;
flags |= gifh1->flags & 0x87;
gif1->blk_header[i]->flags = flags;
}
blocks++;
}
gifh0->width = width + gifh1->width;
gif0->blks = blocks;
return 0;
}
/*----------------------------------------------------------------------------
* Output GIF image
*----------------------------------------------------------------------------*/
int output_gif(FILE *fp, GIF_data *gif)
{
unsigned int i, step;
GIF_imgheader *imgh;
char trailer;
if (!gif || !gif->header) return -1;
// output Header
fwrite(gif->header, 1, GIF_header_size, fp);
// Global Color Table
if (gif->gctbl_size)
fwrite(gif->gctbl, 1, gif->gctbl_size, fp);
// output image blocks
for(i=0; i<(gif->blks); i++) {
imgh = gif->blk_header[i];
step = gif->step_left[i];
imgh->left += step;
fwrite(imgh, 1, GIF_imgheader_size, fp);
imgh->left -= step;
// Local color table
if (gif->lctbl_size[i])
fwrite(gif->lctbl[i], 1, gif->lctbl_size[i], fp);
// output remain
fwrite(((char *)imgh)+GIF_imgheader_size, 1, gif->blk_size[i] - GIF_imgheader_size, fp);
}
// Trailer
trailer = 0x3b;
fwrite(&trailer, 1, 1, fp);
return 0;
}
/*----------------------------------------------------------------------------
* main for debug
*----------------------------------------------------------------------------*/
/*
int main(int argc, char *argv[]) {
int x;
GIF_data gifimg;
GIF_data gif0, gif1, gif2, gif3, gif4, gif5, gif6, gif7, gif8, gif9;
load_gifimg("001/0.gif", &gif0);
load_gifimg("001/1.gif", &gif1);
load_gifimg("001/2.gif", &gif2);
load_gifimg("001/3.gif", &gif3);
load_gifimg("001/4.gif", &gif4);
load_gifimg("001/5.gif", &gif5);
load_gifimg("001/6.gif", &gif6);
load_gifimg("001/7.gif", &gif7);
load_gifimg("001/8.gif", &gif8);
load_gifimg("001/9.gif", &gif9);
copy_GIF_header(&gifimg, &gif0);
catgif_right(&gifimg, &gif1);
catgif_right(&gifimg, &gif0);
catgif_right(&gifimg, &gif2);
catgif_right(&gifimg, &gif3);
catgif_right(&gifimg, &gif5);
catgif_right(&gifimg, &gif9);
catgif_right(&gifimg, &gif8);
catgif_right(&gifimg, &gif4);
catgif_right(&gifimg, &gif7);
catgif_right(&gifimg, &gif4);
catgif_right(&gifimg, &gif3);
x = open("test.gif", O_RDWR | O_CREAT | O_TRUNC);
output_gif(x, &gifimg);
close(x);
return 0;
}
*/
/*
* gifcat.h
*/
#define GIF_MAX_BLOCKS 24
#define GIF_MAX_SIZE 0x40000 // 256KB
/* GIF Headers --------------------------------------------------*/
#define GIF_header_size 13
typedef struct _gif_header {
char signature[3];
char version[3];
unsigned short width;
unsigned short height;
unsigned char flags;
unsigned char bg_index;
unsigned char aspect;
} __attribute__ ((packed)) GIF_header;
#define GIF_imgheader_size 10
typedef struct _gif_imgheader {
char separator; /* 0x2c */
unsigned short left;
unsigned short top;
unsigned short width;
unsigned short height;
unsigned char flags;
} __attribute__ ((packed)) GIF_imgheader;
typedef struct _gif_data {
GIF_header *header;
unsigned char *gctbl;
unsigned int gctbl_size;
unsigned int blks;
GIF_imgheader *blk_header[GIF_MAX_BLOCKS];
unsigned int blk_size [GIF_MAX_BLOCKS]; // without local color table
unsigned int step_left [GIF_MAX_BLOCKS];
unsigned char *lctbl [GIF_MAX_BLOCKS];
unsigned int lctbl_size [GIF_MAX_BLOCKS];
} __attribute__ ((packed)) GIF_data;
/*--- Functions ---------------------------------------------------*/
int init_gifimg(GIF_data *gif);
int load_gifimg(const char *fname, GIF_data *gif);
int copy_GIF_header(GIF_data *gif0, GIF_data *gif1);
int catgif_right(GIF_data *gif0, GIF_data *gif1);
int output_gif(FILE *fp, GIF_data *gif);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment