Last active
December 1, 2015 11:53
-
-
Save nabe-abk/54ee2afb4c5b26d82dff to your computer and use it in GitHub Desktop.
GIF cat ( x86 only )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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; | |
} | |
*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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