From: Robert K. <may...@us...> - 2001-06-14 23:05:53
|
Update of /cvsroot/bitcollider/bitcollider/image In directory usw-pr-cvs1:/tmp/cvs-serv2531 Modified Files: image.c Log Message: Updated image.c -- it now supports bmp, gif and jpg! Index: image.c =================================================================== RCS file: /cvsroot/bitcollider/bitcollider/image/image.c,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -r1.3 -r1.4 *** image.c 2001/06/06 21:49:04 1.3 --- image.c 2001/06/14 23:05:49 1.4 *************** *** 1,306 **** ! /* (PD) 2001 Mark Nelson [delirium] -> del...@th... ! * Please see file COPYING or http://bitzi.com/publicdomain ! * for more info. ! * ! * v0.1.0 - 30 May 2001 - Initial version, supports BMP (Bitmaps) ! * v0.1.1 - 01 Jun 2001 - Added endian-safe portable input functions ! * v0.2.0 - 04 Jun 2001 - Added support for GIF (CompuServe Graphics Interchange Format) ! */ ! ! #include <stdio.h> ! #include <string.h> ! #include <stdlib.h> ! #include <assert.h> ! #include <errno.h> ! ! #include "plugin.h" ! ! ! /*--32-bit Specific Definitions of Portable Data Types---------------------*/ ! ! typedef unsigned char uint8; ! typedef unsigned short uint16; ! typedef unsigned uint32; ! ! /*--Prototypes-------------------------------------------------------------*/ ! ! /* external plugin functions */ ! PluginMethods *init_plugin(void); ! static void image_shutdown_plugin(void); ! static void image_free_attributes(Attribute *attrList); ! static SupportedFormat *image_get_supported_formats(void); ! static const char *image_get_name(void); ! static const char *image_get_version(void); ! static char *image_get_error(void); ! static Attribute *image_file_analyze(const char *fileName); ! ! /* datafile parsing functions */ ! int parse_bmp(FILE *file, uint32 *width, uint32 *height, uint16 *bpp); ! int parse_gif(FILE *file, uint32 *width, uint32 *height, uint16 *bpp); ! ! /* endian-safe input functions */ ! uint8 read_8(FILE *file); ! uint16 read_16_big_endian(FILE *file); ! uint16 read_16_little_endian(FILE *file); ! uint32 read_32_big_endian(FILE *file); ! uint32 read_32_little_endian(FILE *file); ! ! /*--Plugin Parameters------------------------------------------------------*/ ! ! #define PLUGIN_VERSION "0.2.0" ! #define PLUGIN_NAME "Image metadata (BMP, GIF)" ! #define NUM_ATTRS 4 ! ! /*--Cross Platform Foo-----------------------------------------------------*/ ! ! #ifdef _WIN32 ! #define strcasecmp stricmp ! #undef WORDS_BIGENDIAN ! #else ! #include "../config.h" ! #endif ! ! #ifdef WORDS_BIGENDIAN ! # define BIGENDIAN 1 ! #else ! # define BIGENDIAN 0 ! #endif ! ! /*--Plugin Info------------------------------------------------------------*/ ! ! static SupportedFormat formats[] = ! { ! { ".bmp", "BMP (Windows Bitmap) image" }, ! { ".gif", "GIF (CompuServe Graphics Interchange Format) image" }, ! { NULL , NULL } ! }; ! ! static char *errorString = NULL; ! ! static PluginMethods methods = ! { ! image_shutdown_plugin, ! image_get_version, ! image_get_name, ! image_get_supported_formats, ! image_file_analyze, ! NULL, /* no init/update/final */ ! NULL, ! NULL, ! image_free_attributes, ! image_get_error ! }; ! ! /*--Externally-called Plugin Functions-------------------------------------*/ ! ! PluginMethods *init_plugin(void) ! { ! return &methods; ! } ! ! static void image_shutdown_plugin(void) ! { ! if (errorString) ! free(errorString); ! } ! ! static const char *image_get_version(void) ! { ! return PLUGIN_VERSION; ! } ! ! static const char *image_get_name(void) ! { ! return PLUGIN_NAME; ! } ! ! static SupportedFormat *image_get_supported_formats(void) ! { ! return formats; ! } ! ! static Attribute *image_file_analyze(const char *fileName) ! { ! FILE *file; ! Attribute *attrList; ! char temp[100]; ! char *ext; ! int errorcode = 1; ! ! uint32 width; ! uint32 height; ! uint16 bpp; ! ! file = fopen(fileName, "rb"); ! if(file == NULL) ! return NULL; ! ! ext = strrchr(fileName, '.'); ! ! if(strcasecmp(ext,".bmp") == 0) ! errorcode = parse_bmp(file, &width, &height, &bpp); ! else if(strcasecmp(ext, ".gif") == 0) ! errorcode = parse_gif(file, &width, &height, &bpp); ! ! fclose(file); ! ! if(errorcode || width==0 || height==0 || bpp==0) ! return NULL; ! ! /* by this point we should have valid info, so return it */ ! attrList = malloc(sizeof(Attribute) * NUM_ATTRS); ! memset(attrList, 0, sizeof(Attribute) * NUM_ATTRS); ! ! sprintf(temp, "%d", width); ! attrList[0].key = strdup("tag.image.width"); ! attrList[0].value = strdup(temp); ! ! sprintf(temp, "%d", height); ! attrList[1].key = strdup("tag.image.height"); ! attrList[1].value = strdup(temp); ! ! sprintf(temp, "%d", bpp); ! attrList[2].key = strdup("tag.image.bpp"); ! attrList[2].value = strdup(temp); ! ! return attrList; ! } ! ! static void image_free_attributes(Attribute *attrList) ! { ! int i; ! ! for(i = 0; i < NUM_ATTRS; i++) ! { ! if (attrList[i].key) ! free(attrList[i].key); ! if (attrList[i].value) ! free(attrList[i].value); ! } ! ! free(attrList); ! } ! ! static char *image_get_error(void) ! { ! return errorString; ! } ! ! /*--Functions to Parse Files for Width/Height/BPP info---------------------*/ ! ! /* All functions return 0 on success and 1 if file is not a valid file of that type */ ! ! int parse_bmp(FILE *file, uint32 *width, uint32 *height, uint16 *bpp) ! { ! /* File must start with "BM" */ ! if(read_8(file) != 'B' || read_8(file) != 'M') ! return 1; ! ! fseek(file, 16L, SEEK_CUR); ! ! #if BIGENDIAN ! *width = read_32_big_endian(file); ! *height = read_32_big_endian(file); ! fseek(file, 2L, SEEK_CUR); ! *bpp = read_16_big_endian(file); ! #else ! *width = read_32_little_endian(file); ! *height = read_32_little_endian(file); ! fseek(file, 2L, SEEK_CUR); ! *bpp = read_16_little_endian(file); ! #endif ! ! return 0; ! } ! ! int parse_gif(FILE *file, uint32 *width, uint32 *height, uint16 *bpp) ! { ! unsigned char packed; ! uint16 bpp1, bpp2; ! ! /* File must start with "GIF" */ ! if(read_8(file) != 'G' || read_8(file) != 'I' || read_8(file) != 'F') ! return 1; ! ! fseek(file, 3L, SEEK_CUR); ! #if BIGENDIAN ! *width = (uint32) read_16_big_endian(file); ! *height = (uint32) read_16_big_endian(file); ! #else ! *width = (uint32) read_16_little_endian(file); ! *height = (uint32) read_16_little_endian(file); ! #endif ! ! /* packed byte: ! Bits 8 and 5 are flags we don't need to worry about; ! bits 6-8 and 1-3 are 3-bit descriptions of the number of bits, ! minus 1, of "color resolution" and "bits per pixel" respectively. ! Usually these values are the same, but if they're not, take the ! larger of the two to be "bpp," since this is what standard ! image editing programs seem to do. I don't know why. ! */ ! packed = read_8(file); ! bpp1 = ((packed & 0x70) >> 4) + 1; ! bpp2 = (packed & 0x07) + 1; ! ! if(bpp1 > bpp2) ! *bpp = bpp1; ! else ! *bpp = bpp2; ! ! return 0; ! } ! ! /*--Endian-Safe Input Functions--------------------------------------------*/ ! ! uint8 read_8(FILE *file) ! { ! uint8 a; ! ! if((a=getc(file))==(uint8)EOF) ! return 0; ! ! return a; ! } ! ! uint16 read_16_big_endian(FILE *file) ! { ! uint16 a,b; ! ! if((a=getc(file))==(uint16)EOF || (b=getc(file))==(uint16)EOF) ! return 0; ! ! return ((a<<8) + b); ! } ! ! uint16 read_16_little_endian(FILE *file) ! { ! uint16 a,b; ! ! if((a=getc(file))==(uint16)EOF || (b=getc(file))==(uint16)EOF) ! return 0; ! ! return ((b<<8) + a); ! } ! ! uint32 read_32_big_endian(FILE *file) ! { ! uint32 a,b,c,d; ! ! if((a=getc(file))==(uint32)EOF || (b=getc(file))==(uint32)EOF || ! (c=getc(file))==(uint32)EOF || (d=getc(file))==(uint32)EOF) ! return 0; ! ! return ((a<<24) + (b<<16) + (c<<8) + d); ! } ! ! uint32 read_32_little_endian(FILE *file) ! { ! uint32 a,b,c,d; ! ! if((a=getc(file))==(uint32)EOF || (b=getc(file))==(uint32)EOF || ! (c=getc(file))==(uint32)EOF || (d=getc(file))==(uint32)EOF) ! return 0; ! ! return ((d<<24) + (c<<16) + (b<<8) + a); ! } --- 1,377 ---- ! /* (PD) 2001 Mark Nelson [delirium] -> del...@th... ! * Please see file COPYING or http://bitzi.com/publicdomain ! * for more info. ! * ! * Revision history: ! * v0.1.0 - 30 May 2001 - Initial version, supports BMP (Bitmaps) ! * v0.1.1 - 01 Jun 2001 - Added endian-safe portable input functions ! * v0.2.0 - 04 Jun 2001 - Added support for GIF (CompuServe Graphics Interchange Format) ! * v0.3.0 - 13 Jun 2001 - Added support for JPEG/JFIF ! */ ! ! #include <stdio.h> ! #include <string.h> ! #include <stdlib.h> ! #include <assert.h> ! #include <errno.h> ! ! #include "plugin.h" ! ! ! /*--32-bit Specific Definitions of Portable Data Types---------------------*/ ! ! typedef unsigned char uint8; ! typedef unsigned short uint16; ! typedef unsigned uint32; ! ! /*--Prototypes-------------------------------------------------------------*/ ! ! /* external plugin functions */ ! PluginMethods *init_plugin(void); ! static void image_shutdown_plugin(void); ! static void image_free_attributes(Attribute *attrList); ! static SupportedFormat *image_get_supported_formats(void); ! static const char *image_get_name(void); ! static const char *image_get_version(void); ! static char *image_get_error(void); ! static Attribute *image_file_analyze(const char *fileName); ! ! /* datafile parsing functions */ ! int parse_bmp(FILE *file, uint32 *width, uint32 *height, uint16 *bpp); ! int parse_gif(FILE *file, uint32 *width, uint32 *height, uint16 *bpp); ! int parse_jpg(FILE *file, uint32 *width, uint32 *height, uint16 *bpp); ! ! /* endian-safe input functions */ ! uint8 read_8(FILE *file); ! uint16 read_16_big_endian(FILE *file); ! uint16 read_16_little_endian(FILE *file); ! uint32 read_32_big_endian(FILE *file); ! uint32 read_32_little_endian(FILE *file); ! ! /*--Plugin Parameters------------------------------------------------------*/ ! ! #define PLUGIN_VERSION "0.3.0" ! #define PLUGIN_NAME "Image metadata (BMP, GIF, JPEG)" ! #define NUM_ATTRS 4 ! ! /*--Cross Platform Foo-----------------------------------------------------*/ ! ! #ifdef _WIN32 ! #define strcasecmp stricmp ! #else ! #include "../config.h" ! #endif ! ! /*--Plugin Info------------------------------------------------------------*/ ! ! static SupportedFormat formats[] = ! { ! { ".bmp" , "Windows Bitmap image" }, ! { ".gif" , "CompuServe Graphics Interchange Format (GIF) image" }, ! { ".jpg" , "JPEG/JFIF compressed image" }, ! { ".jpeg", "JPEG/JFIF compressed image" }, ! { NULL , NULL } ! }; ! ! static char *errorString = NULL; ! ! static PluginMethods methods = ! { ! image_shutdown_plugin, ! image_get_version, ! image_get_name, ! image_get_supported_formats, ! image_file_analyze, ! NULL, /* no init/update/final */ ! NULL, ! NULL, ! image_free_attributes, ! image_get_error ! }; ! ! /*--Externally-called Plugin Functions-------------------------------------*/ ! ! PluginMethods *init_plugin(void) ! { ! return &methods; ! } ! ! static void image_shutdown_plugin(void) ! { ! if (errorString) ! free(errorString); ! } ! ! static const char *image_get_version(void) ! { ! return PLUGIN_VERSION; ! } ! ! static const char *image_get_name(void) ! { ! return PLUGIN_NAME; ! } ! ! static SupportedFormat *image_get_supported_formats(void) ! { ! return formats; ! } ! ! static Attribute *image_file_analyze(const char *fileName) ! { ! FILE *file; ! Attribute *attrList; ! char temp[100]; ! char *ext; ! int errorcode = 1; ! ! uint32 width; ! uint32 height; ! uint16 bpp; ! ! file = fopen(fileName, "rb"); ! if(file == NULL) ! return NULL; ! ! ext = strrchr(fileName, '.'); ! ! if(strcasecmp(ext,".bmp") == 0) ! errorcode = parse_bmp(file, &width, &height, &bpp); ! else if(strcasecmp(ext, ".gif") == 0) ! errorcode = parse_gif(file, &width, &height, &bpp); ! else if(strcasecmp(ext, ".jpg") == 0) ! errorcode = parse_jpg(file, &width, &height, &bpp); ! else if(strcasecmp(ext, ".jpeg") == 0) ! errorcode = parse_jpg(file, &width, &height, &bpp); ! ! fclose(file); ! ! if(errorcode || width==0 || height==0 || bpp==0) ! return NULL; ! ! /* by this point we should have valid info, so return it */ ! attrList = malloc(sizeof(Attribute) * NUM_ATTRS); ! memset(attrList, 0, sizeof(Attribute) * NUM_ATTRS); ! ! sprintf(temp, "%d", width); ! attrList[0].key = strdup("tag.image.width"); ! attrList[0].value = strdup(temp); ! ! sprintf(temp, "%d", height); ! attrList[1].key = strdup("tag.image.height"); ! attrList[1].value = strdup(temp); ! ! sprintf(temp, "%d", bpp); ! attrList[2].key = strdup("tag.image.bpp"); ! attrList[2].value = strdup(temp); ! ! return attrList; ! } ! ! static void image_free_attributes(Attribute *attrList) ! { ! int i; ! ! for(i = 0; i < NUM_ATTRS; i++) ! { ! if (attrList[i].key) ! free(attrList[i].key); ! if (attrList[i].value) ! free(attrList[i].value); ! } ! ! free(attrList); ! } ! ! static char *image_get_error(void) ! { ! return errorString; ! } ! ! /*--Functions to Parse Files for Width/Height/BPP info---------------------*/ ! ! /* All functions return 0 on success and 1 if file is not a valid file of that type */ ! ! int parse_bmp(FILE *file, uint32 *width, uint32 *height, uint16 *bpp) ! { ! /* File must start with "BM" */ ! if(read_8(file) != 'B' || read_8(file) != 'M') ! return 1; ! ! fseek(file, 16L, SEEK_CUR); ! ! *width = read_32_little_endian(file); ! *height = read_32_little_endian(file); ! fseek(file, 2L, SEEK_CUR); ! *bpp = read_16_little_endian(file); ! ! return 0; ! } ! ! int parse_gif(FILE *file, uint32 *width, uint32 *height, uint16 *bpp) ! { ! unsigned char packed; ! uint16 bpp1, bpp2; ! ! /* File must start with "GIF" */ ! if(read_8(file) != 'G' || read_8(file) != 'I' || read_8(file) != 'F') ! return 1; ! ! fseek(file, 3L, SEEK_CUR); ! *width = (uint32) read_16_little_endian(file); ! *height = (uint32) read_16_little_endian(file); ! ! /* packed byte: ! Bits 8 and 5 are flags we don't need to worry about; ! bits 6-8 and 1-3 are 3-bit descriptions of the number of bits, ! minus 1, of "color resolution" and "bits per pixel" respectively. ! Usually these values are the same, but if they're not, take the ! larger of the two to be "bpp," since this is what standard ! image editing programs seem to do. I don't know why. ! */ ! packed = read_8(file); ! bpp1 = ((packed & 0x70) >> 4) + 1; ! bpp2 = (packed & 0x07) + 1; ! ! if(bpp1 > bpp2) ! *bpp = bpp1; ! else ! *bpp = bpp2; ! ! return 0; ! } ! ! int parse_jpg(FILE *file, uint32 *width, uint32 *height, uint16 *bpp) ! { ! uint16 bytes_left=0; ! ! /* File must start with 0xFFD8FFE0, <2 byte field length>, "JFIF", 0x00 */ ! if(read_8(file) != 0xFF || read_8(file) != 0xD8 || ! read_8(file) != 0xFF || read_8(file) != 0xE0) ! return 1; ! ! bytes_left = read_16_big_endian(file); ! bytes_left -= 2; /* the 2 bytes of the field length indicator itself count */ ! ! if(read_8(file) != 'J' || read_8(file) != 'F' || read_8(file) != 'I' || ! read_8(file) != 'F' || read_8(file) != 0x00) ! return 1; ! ! bytes_left -= 5; ! ! /* skip past the rest of the JFIF indicator field */ ! fseek(file, bytes_left, SEEK_CUR); ! ! /* now we parse the file for the image information field. JPEG fields ! have the general structure of: 0xFF, <1 byte field type>, <2 byte field ! length>, <x byte field data> */ ! while(!feof(file)) ! { ! uint8 type, samples, bits_per_sample; ! ! /* if there's no 0xFF marker, JPEG file is malformed */ ! if(read_8(file) != 0xFF) ! return 1; ! /* JPEG files are sometimes padded with sequential 0xFF bytes */ ! do ! { ! type = read_8(file); ! } while (type == 0xFF); ! ! switch (type) { ! /* image information fields (for various types of compression) */ ! case 0xC0: ! case 0xC1: ! case 0xC2: ! case 0xC3: ! case 0xC5: ! case 0xC6: ! case 0xC7: ! case 0xC9: ! case 0xCA: ! case 0xCB: ! case 0xCD: ! case 0xCE: ! case 0xCF: ! fseek(file, 2L, SEEK_CUR); /* skip the field length */ ! bits_per_sample = read_8(file); ! *height = (uint32) read_16_big_endian(file); ! *width = (uint32) read_16_big_endian(file); ! samples = read_8(file); ! *bpp = (uint16) samples * bits_per_sample; ! return 0; ! ! case 0xD9: /* if end of image, */ ! case 0xDA: /* or beginning of compressed data, */ ! return 1; /* there was no image info (or we missed it) */ ! ! /* if any other field, we don't care, so skip past it */ ! default: ! bytes_left = read_16_big_endian(file); ! /* since the length takes 2 bytes, length must be >= 2 */ ! if (bytes_left < 2) ! return 1; ! bytes_left -= 2; ! ! /* skip the rest of the field and go on the next one */ ! fseek(file, bytes_left, SEEK_CUR); ! break; ! } ! } ! return 1; ! } ! ! /*--Endian-Safe Input Functions--------------------------------------------*/ ! ! uint8 read_8(FILE *file) ! { ! uint8 a; ! ! a=getc(file); ! ! return a; ! } ! ! uint16 read_16_big_endian(FILE *file) ! { ! uint16 a,b; ! ! a=getc(file); ! b=getc(file); ! ! return ((a<<8) + b); ! } ! ! uint16 read_16_little_endian(FILE *file) ! { ! uint16 a,b; ! ! a=getc(file); ! b=getc(file); ! ! return ((b<<8) + a); ! } ! ! uint32 read_32_big_endian(FILE *file) ! { ! uint32 a,b,c,d; ! ! a=getc(file); ! b=getc(file); ! c=getc(file); ! d=getc(file); ! ! return ((a<<24) + (b<<16) + (c<<8) + d); ! } ! ! uint32 read_32_little_endian(FILE *file) ! { ! uint32 a,b,c,d; ! ! a=getc(file); ! b=getc(file); ! c=getc(file); ! d=getc(file); ! ! return ((d<<24) + (c<<16) + (b<<8) + a); ! } |