Created
June 19, 2012 19:16
-
-
Save sebbu2/2955990 to your computer and use it in GitHub Desktop.
Fast Image Size Reader
This file contains hidden or 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
#include <vector> | |
#include <cerrno> | |
#include <climits> | |
#include "fast_image_size_reader.hpp" | |
#include "crc32.hpp" | |
enum file_type get_file_type(const char* filename) { | |
assert(strcmp(filename,"")!=0); | |
enum file_type res=UNKNOWN; | |
FILE* fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return UNKNOWN; | |
} | |
//uint8_t f2[2]; | |
uint8_t f8[9]; | |
//int res=fread(f2, 2, 1, fp); | |
size_t result=fread(f8, 8, 1, fp); | |
//fprintf(stderr, "%02X %02X\n", f2[0], f2[1]); | |
//fprintf(stderr, "%02X %02X %02X %02X %02X %02X %02X %02X\n", f8[0], f8[1], f8[2], f8[3], f8[4], f8[5], f8[6], f8[7]); | |
assert(result==1); | |
uint8_t f26[27];//new TGA only | |
result=fread(f26, 26, 1, fp); | |
assert(result==1); | |
size_t len=strlen(filename); | |
if (strncmp((char*)f8, "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a", 8)==0) { //PNG | |
//printf("File = '%s' Type = PNG\n", filename); | |
res=PNG; | |
} | |
else if (strncmp((char*)f8, "\xFF\xD8\xFF\xE0", 4)==0) { //JPG | |
//printf("File = '%s' Type = JPG\n", filename); | |
res=JPG; | |
} | |
else if (strncmp((char*)f8, "BM", 2)==0) { //BMP | |
//printf("File = '%s' Type = BMP\n", filename); | |
res=BMP; | |
} | |
else if (strncmp((char*)f8, "GIF", 3)==0) { //GIF | |
assert(strncmp((char*)f8+3,"87a", 3)==0 || strncmp((char*)f8+3,"89a", 3)==0); //can be either of the 2 version | |
//printf("File = '%s' Type = GIF\n", filename); | |
res=GIF; | |
} | |
else if (memcmp((char*)f8, "II\x2A\0", 4)==0) { //TIF | |
//printf("File = '%s' Type = TIF\n", filename); | |
res=TIF; | |
} | |
else if (memcmp((char*)f8, "MM\0\x2A", 4)==0) { //TIF | |
//printf("File = '%s' Type = TIF\n", filename); | |
res=TIF; | |
//printf("Type = UNKNOWN\n"); | |
//res=UNKNOWN; | |
} | |
//VDA,ICB,TGA,VST | |
else if (memcmp((char*)f26+8, "TRUEVISION-XFILE.\0", 18)==0) { //new TGA | |
//printf("File = '%s' Type = TGA\n", filename); | |
res=TGA; | |
} | |
else if (f8[2]=='\x00' || f8[2]=='\x01' || f8[2]=='\x02' || f8[2]=='\x03' || f8[2]=='\x09' || f8[2]=='\x0A' || f8[2]=='\x0B' || f8[2]=='\x20' || f8[2]=='\x21') { | |
//not enough to be sure, extension check | |
if (strncmp(filename+len-4, ".tga", 4)==0 || strncmp(filename+len-4, ".vda", 4)==0 || strncmp(filename+len-4, ".icb", 4)==0 || strncmp(filename+len-4, ".vst", 4)==0 || strncmp(filename+len-5, ".tpic", 5)==0) { | |
//printf("File = '%s' Type = TGA OLD\n", filename); | |
res=TGA_OLD; | |
} | |
else { | |
printf("File = '%s' Type = UNKNOWN\n", filename); | |
} | |
} | |
//fprintf(stderr, "[DEBUG] filename+len-4 = %s\n", filename+len-4); | |
fclose(fp); | |
return res; | |
} | |
uint64_t get_file_dim(const char* filename) { | |
assert(strcmp(filename,"")!=0); | |
//uint64_t res=0; | |
enum file_type ft=get_file_type(filename); | |
return get_file_dim2(filename, ft); | |
//return res;//depreciated in my case | |
} | |
uint64_t get_file_dim2(const char* filename, enum file_type ft) { | |
uint64_t res=0; | |
FILE* fp=NULL; | |
switch (ft) { //print the file type | |
case PNG: | |
fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return res; | |
} | |
fseek(fp, 8, SEEK_SET);//header already checked by get_file_type | |
res=get_file_dim_png(fp); | |
fclose(fp); | |
break; | |
case JPG: | |
fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return res; | |
} | |
fseek(fp, 4, SEEK_SET);//header already checked by get_file_type | |
res=get_file_dim_jpg(fp); | |
fclose(fp); | |
break; | |
case BMP: | |
fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return res; | |
} | |
fseek(fp, 2, SEEK_SET);//header already checked by get_file_type | |
res=get_file_dim_bmp(fp); | |
fclose(fp); | |
break; | |
case GIF: | |
fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return res; | |
} | |
fseek(fp, 6, SEEK_SET);//header already checked by get_file_type | |
res=get_file_dim_gif(fp); | |
fclose(fp); | |
break; | |
case TIF: | |
fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return res; | |
} | |
fseek(fp, 4, SEEK_SET);//header already checked by get_file_type | |
res=get_file_dim_tif(fp); | |
fclose(fp); | |
break; | |
case TGA: | |
fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return res; | |
} | |
//ext start | |
fseek(fp, -26, SEEK_END);//extension area offset + developer directory offset//8 bytes only, rest is signature (already treated) | |
res=get_file_dim_tga(fp); | |
//ext end | |
//old start | |
//res=get_file_dim_tga_old(fp);//read new as well | |
//old end | |
fclose(fp); | |
break; | |
case TGA_OLD: | |
fp=fopen(filename, "rb"); | |
if (fp==NULL) { | |
return res; | |
} | |
//seek to 0 == N/A | |
res=get_file_dim_tga_old(fp);//read new as well | |
fclose(fp); | |
break; | |
case UNKNOWN: | |
printf("UNKNOWN\n"); | |
break; | |
default: | |
printf("UNKNOWN and untreated : %d\n", get_file_type(filename)); //second call | |
break; | |
} | |
return res; | |
} | |
typedef unsigned char uchar; | |
uint64_t get_file_dim_png(FILE* fp) { | |
uchar chunk_size[5]; | |
size_t read=fread(chunk_size, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int chunk_s= ((unsigned)chunk_size[0]<<24) | ((unsigned)chunk_size[1]<<16) | ((unsigned)chunk_size[2]<<8) | chunk_size[3]; | |
assert(chunk_s == 13); //first chunk should be IHDR, which is 13 bytes long | |
//read chunk type | |
uchar chunk_type[5]; | |
read=fread(chunk_type, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
assert(strncmp((char*)chunk_type, "IHDR", 4)==0); //is IHDR | |
//read data part 1 (width) | |
uchar width_s[5]; | |
read=fread(width_s, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int width=((unsigned)width_s[0]<<24)|((unsigned)width_s[1]<<16)|((unsigned)width_s[2]<<8)|width_s[3]; | |
//read data part 2 (height) | |
uchar height_s[5]; | |
read=fread(height_s, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int height=((unsigned)height_s[0]<<24)|((unsigned)height_s[1]<<16)|((unsigned)height_s[2]<<8)|height_s[3]; | |
//read data part 3 (bit depth, colour type, compression method, filter method, interlace method | |
uchar data_p3[6]; | |
read=fread(data_p3, 5, 1, fp); | |
assert(read==1); //read 1 * 5 bytes | |
uchar bit_depth=data_p3[0]; | |
uchar colour_type=data_p3[1]; | |
assert( | |
(colour_type==0 && (bit_depth==1||bit_depth==2||bit_depth==4||bit_depth==8||bit_depth==16)) || | |
(colour_type==2 && (bit_depth==8||bit_depth==16)) || | |
(colour_type==3 && (bit_depth==1||bit_depth==2||bit_depth==4||bit_depth==8)) || | |
(colour_type==4 && (bit_depth==8||bit_depth==16)) || | |
(colour_type==6 && (bit_depth==8||bit_depth==16)) | |
);//allowed combinaison | |
uchar compression_method=data_p3[2]; | |
assert(compression_method==0); //deflate/inflate compression with a sliding window of at most 32768 bytes | |
uchar filter_method=data_p3[3]; | |
assert(filter_method==0); //adaptive filtering with five basic filter types | |
uchar interlace_method=data_p3[4]; | |
assert(interlace_method==0 || interlace_method==1); //no interlace || Adam7 interlace | |
//read CRC | |
uchar crc_s[5]; | |
read=fread(crc_s, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int crc_f=(unsigned)crc_s[0]<<24|(unsigned)crc_s[1]<<16|(unsigned)crc_s[2]<<8|(unsigned)crc_s[3]; | |
//printf("crc_f = %X\n", crc_f); | |
//calculate CRC | |
unsigned long crc2=update_crc(0xffffffffL, chunk_type, 4); | |
crc2=update_crc(crc2, width_s, 4); | |
crc2=update_crc(crc2, height_s, 4); | |
crc2=update_crc(crc2, data_p3, 5); | |
crc2^=0xffffffffL; | |
//printf("crc2 = %lX\n", crc2); | |
assert(crc_f==crc2); //should be egal | |
return (uint64_t)(((uint64_t)width<<32)|(uint64_t)height); | |
} | |
#define M_SOF0 0xC0 /* Start Of Frame N */ | |
#define M_SOF1 0xC1 /* N indicates which compression process */ | |
#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ | |
#define M_SOF3 0xC3 | |
#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ | |
#define M_SOF6 0xC6 | |
#define M_SOF7 0xC7 | |
#define M_SOF9 0xC9 | |
#define M_SOF10 0xCA | |
#define M_SOF11 0xCB | |
#define M_SOF13 0xCD | |
#define M_SOF14 0xCE | |
#define M_SOF15 0xCF | |
#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ | |
#define M_EOI 0xD9 /* End Of Image (end of datastream) */ | |
#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ | |
#define M_APP0 0xE0 /* Application-specific marker, type N */ | |
#define M_APP1 0xE1 | |
#define M_APP2 0xE2 | |
#define M_APP3 0xE3 | |
#define M_APP4 0xE4 | |
#define M_APP5 0xE5 | |
#define M_APP6 0xE6 | |
#define M_APP7 0xE7 | |
#define M_APP8 0xE8 | |
#define M_APP9 0xE9 | |
#define M_APP10 0xEA | |
#define M_APP11 0xEB | |
#define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */ | |
#define M_COM 0xFE /* COMment */ | |
uint64_t get_file_dim_jpg(FILE* fp) { | |
uchar app0_ls[2]; | |
size_t read=fread(app0_ls, 2, 1, fp); | |
assert(read == 1); | |
short app0_l=(short)((short)app0_ls[0]<<8|(short)app0_ls[1]); | |
//later assert | |
uchar ident_s[6]; | |
read=fread(ident_s, 5, 1, fp); | |
assert(read==1); | |
assert(strncmp((char*)ident_s, "JFIF\0", 5)==0); | |
uchar rev_s[3]; | |
read=fread(rev_s, 2, 1, fp); | |
assert(read==1); | |
uchar unit=(unsigned char)'\xFF'; | |
read=fread(&unit, 1, 1, fp); | |
assert(read==1); | |
uchar xdens_s[3]; | |
read=fread(xdens_s, 2, 1, fp); | |
assert(read==1); | |
uchar ydens_s[3]; | |
read=fread(ydens_s, 2, 1, fp); | |
assert(read==1); | |
uchar xth='\x00'; | |
read=fread(&xth, 1, 1, fp); | |
assert(read==1); | |
uchar yth='\x00'; | |
read=fread(&yth, 1, 1, fp); | |
assert(read==1); | |
//app0 assert | |
assert(app0_l == (16+3*xth*yth)); | |
//finished reading header | |
unsigned int marker=0; | |
unsigned int length=0; | |
int data_precision=-1; | |
unsigned int image_height=0; | |
unsigned int image_width=0; | |
int num_components=-1; | |
int loop=1; | |
//for(;;) {//infinite loop with breaks | |
while (loop==1) { | |
uchar tmp[3]; | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); | |
assert((uchar)tmp[0] == 0xFF); | |
marker=tmp[1]; | |
switch (marker) { | |
case M_EOI: | |
case M_SOI: | |
case M_SOS: | |
loop=0; | |
break; | |
case M_SOF0: /* Baseline */ | |
case M_SOF1: /* Extended sequential, Huffman */ | |
case M_SOF2: /* Progressive, Huffman */ | |
case M_SOF3: /* Lossless, Huffman */ | |
case M_SOF5: /* Differential sequential, Huffman */ | |
case M_SOF6: /* Differential progressive, Huffman */ | |
case M_SOF7: /* Differential lossless, Huffman */ | |
case M_SOF9: /* Extended sequential, arithmetic */ | |
case M_SOF10: /* Progressive, arithmetic */ | |
case M_SOF11: /* Lossless, arithmetic */ | |
case M_SOF13: /* Differential sequential, arithmetic */ | |
case M_SOF14: /* Differential progressive, arithmetic */ | |
case M_SOF15: /* Differential lossless, arithmetic */ | |
//do_process_SOFn(fp, marker); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); | |
//printf("length: %02X%02X\n", tmp[0], tmp[1]); | |
length=(unsigned)tmp[0]<<8|tmp[1]; | |
//length = read_2_bytes(); /* usual parameter length count */ | |
read=fread(tmp, 1, 1, fp); | |
assert(read==1); | |
//printf("data_precision: %02X\n", tmp[0]); | |
data_precision=tmp[0]; | |
//data_precision = read_1_byte(); | |
assert(data_precision>=0); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); | |
//printf("image_height: %02X%02X\n", tmp[0], tmp[1]); | |
image_height = (unsigned)tmp[0]<<8|tmp[1]; | |
//image_height = read_2_bytes(); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); | |
//printf("image_width: %02X%02X\n", tmp[0], tmp[1]); | |
image_width = (unsigned)tmp[0]<<8|tmp[1]; | |
//image_width = read_2_bytes(); | |
read=fread(tmp, 1, 1, fp); | |
assert(read==1); | |
//printf("num_components: %02X\n", tmp[0]); | |
num_components=tmp[0]; | |
if (length != (unsigned int)(8 + num_components * 3)) { | |
fprintf(stderr,"Bogus SOF marker length\n"); | |
//exit(1); | |
} | |
fseek(fp, 3*num_components, SEEK_CUR); | |
break; | |
case M_APP0: | |
case M_APP1: | |
case M_APP2: | |
case M_APP3: | |
case M_APP4: | |
case M_APP5: | |
case M_APP6: | |
case M_APP7: | |
case M_APP8: | |
case M_APP9: | |
case M_APP10: | |
case M_APP11: | |
case M_APP12: | |
case M_COM: | |
default: | |
/* Get the marker parameter length count */ | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); | |
length = (unsigned)tmp[0]<<8|tmp[1]; | |
//length = read_2_bytes(); | |
/* Length includes itself, so must be at least 2 */ | |
if (length < 2) { | |
fprintf(stderr, "Erroneous JPEG marker length\n"); | |
break;//don't exit, return 0 width & height | |
} | |
length -= 2; | |
/* Skip over the remaining bytes */ | |
fseek(fp, (long)length, SEEK_CUR); | |
break; | |
} | |
} | |
return ((uint64_t)image_width<<32|(uint64_t)image_height); | |
} | |
uint64_t get_file_dim_bmp(FILE* fp) { | |
uchar tmp[5]; | |
size_t read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int file_s=((unsigned)tmp[0]<<24)|((unsigned)tmp[1]<<16)|((unsigned)tmp[2]<<8)|tmp[3]; | |
assert(file_s > 0); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
assert(tmp[0]=='\0' && tmp[1]=='\0'); //reserved | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
assert(tmp[0]=='\0' && tmp[1]=='\0'); //reserved | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
//int bfOffBits=tmp[0]<<24|tmp[1]<<16|tmp[2]<<8|tmp[3];//later use | |
unsigned int bfOffBits=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24);//later use | |
//fprintf(stderr, "[DEBUG] bfOffBits = %d\n", bfOffBits); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biSize=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24);//40 | |
assert(biSize==40); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biWidth=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biHeight=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
unsigned short biPlanes=(unsigned short)(tmp[0]|((unsigned short)tmp[1]<<8)); | |
assert(biPlanes==0 || biPlanes==1); //reserved | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
unsigned short biBitCount=(unsigned short)(tmp[0]|((unsigned short)tmp[1]<<8)); | |
//fprintf(stderr, "[DEBUG] biBitCount= %d\n", biBitCount); | |
assert(biBitCount==1 || biBitCount==4 || biBitCount==8 || biBitCount==24); //possible values | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biCompression=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24); | |
assert(biCompression==0); //compression not treated | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biSizeImage=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24);//can be zero | |
//assert( biSizeImage>=0 ); | |
assert(biSizeImage <= UINT_MAX); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biXPelsPerMeter=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24);//can be zero | |
//assert( biXPelsPerMeter>=0 ); | |
assert(biXPelsPerMeter <= UINT_MAX); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biYPelsPerMeter=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24);//can be zero | |
//assert( biYPelsPerMeter>=0 ); | |
assert(biYPelsPerMeter <= UINT_MAX); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biClrUsed=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24);//can be zero | |
//assert( biClrUsed>=0 ); | |
assert(biClrUsed <= UINT_MAX); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int biClrImportant=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24);//can be zero | |
//assert( biClrImportant>=0 ); | |
assert(biClrImportant <= UINT_MAX); | |
//later test | |
assert( | |
(biBitCount==1 && bfOffBits==14+40+4*2) || | |
(biBitCount==4 && bfOffBits==14+40+4*16) || | |
(biBitCount==8 && bfOffBits==14+40+4*256) || | |
(biBitCount==24 && bfOffBits==14+40) | |
); | |
return ((uint64_t)biWidth<<32|(uint64_t)biHeight); | |
} | |
uint64_t get_file_dim_gif(FILE* fp) { | |
uchar tmp[5]; | |
size_t read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
unsigned short biWidth=(unsigned short)(tmp[0]|((unsigned short)tmp[1]<<8)); | |
//fprintf(stderr, "[DEBUG] biWidth = %d\n", biWidth); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
unsigned short biHeight=(unsigned short)(tmp[0]|((unsigned short)tmp[1]<<8)); | |
//fprintf(stderr, "[DEBUG] biHeight = %d\n", biHeight); | |
read=fread(tmp, 1, 1, fp); | |
assert(read==1); | |
uchar ct=(uchar)(tmp[0]>>7); //color table | |
assert(ct==0 || ct==1); //used ! | |
uchar cr=(tmp[0]>>4)&0x07;//bit of color resolution PER primary color | |
++cr; | |
assert(cr>0); | |
//fprintf(stderr, "[DEBUG] bit of color resolution %d\n", cr); | |
uchar st=(tmp[0]>>3&0x01);//sort flag | |
assert(st==0 || st==1); //used ! | |
uchar bp=(tmp[0]&0x07);//bit per pixel | |
++bp; | |
assert(bp>0); | |
//fprintf(stderr, "[DEBUG] bit per pixel %d\n", bp); | |
//background color index (not done) | |
//pixel aspect ratio (not done) | |
return ((uint64_t)biWidth<<32|(uint64_t)biHeight); | |
} | |
uint64_t get_file_dim_tif(FILE* fp) { | |
uchar tmp[5]; | |
size_t read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int offset=tmp[0]|(unsigned)tmp[1]<<8|(unsigned)tmp[2]<<16|(unsigned)tmp[3]<<24; | |
//assert( offset==8 );//standard TIFF//test | |
unsigned int width=0; | |
unsigned int height=0; | |
unsigned int bitsPerSample=0; | |
std::vector<unsigned int> field_tag_v; | |
std::vector<unsigned int> field_type_v; | |
std::vector<unsigned int> length_v; | |
std::vector<unsigned int> data_offset_v; | |
//offset=8;//don't care of the initialized variable == //standard TIFF in my exemples | |
do { | |
fseek(fp, (long)offset, SEEK_SET); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 byte | |
int num=tmp[0]|tmp[1]<<8; | |
for (int i=0; i<num; ++i) { | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
unsigned int field_tag=tmp[0]|(unsigned)tmp[1]<<8; | |
/**/ | |
field_tag_v.push_back(field_tag); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 bytes | |
unsigned int field_type=tmp[0]|(unsigned)tmp[1]<<8; | |
/**/ | |
field_type_v.push_back(field_type); | |
assert(field_type>=1 && field_type<=5); //allowed types | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int length=tmp[0]|(unsigned)tmp[1]<<8|(unsigned)tmp[2]<<16|(unsigned)tmp[3]<<24; | |
/**/ | |
length_v.push_back(length); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int data_offset=tmp[0]|(unsigned)tmp[1]<<8|(unsigned)tmp[2]<<16|(unsigned)tmp[3]<<24; | |
/**/ | |
data_offset_v.push_back(data_offset); | |
} | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
offset=tmp[0]|(unsigned)tmp[1]<<8|(unsigned)tmp[2]<<16|(unsigned)tmp[3]<<24; | |
} | |
while (offset!=0); | |
//fprintf(stderr, "[INFO] vector.size = %d\n", field_tag_v.size()); | |
//search of width, height & BitsPerSample | |
std::vector<unsigned int>::iterator it1, it2; | |
it1=field_tag_v.begin(); | |
it2=field_tag_v.end(); | |
unsigned int i=0; | |
/* field type | |
1 - byte | |
2 - ASCII string, counted in length. | |
Most often an ASCIIZ string, the | |
trailing zero is counted with the | |
data length. | |
3 - word | |
4 - dword / uword | |
5 - rational (2 dwords, numerator and denominator) | |
*/ | |
//offset used only if length > 4 | |
for (; it1!=it2; ++it1,++i) { | |
if (*it1==256) { | |
//width//word or dword | |
assert(field_type_v.at(i)==3 || field_type_v.at(i)==4); | |
assert(data_offset_v.at(i)!=0); //error | |
assert(length_v.at(i)==1); //error | |
width = data_offset_v.at(i); | |
} | |
else if (*it1==257) { | |
//height//word or dword | |
assert(field_type_v.at(i)==3 || field_type_v.at(i)==4); | |
assert(data_offset_v.at(i)!=0); //error | |
assert(length_v.at(i)==1); //error | |
height = data_offset_v.at(i); | |
} | |
else if (*it1==258) { | |
//BitsPerSample//word | |
assert(field_type_v.at(i)==3); //word | |
assert(data_offset_v.at(i)!=0); //error | |
assert(length_v.at(i)==1); //error | |
bitsPerSample = data_offset_v.at(i); | |
assert((/*bitsPerSample>=0 &&*/ bitsPerSample<=4) || bitsPerSample%2==0); | |
} | |
} | |
//fprintf(stderr, "[INFO] bitsPerSample = %d\n", bitsPerSample); | |
return ((uint64_t)width<<32|(uint64_t)height); | |
} | |
uint64_t get_file_dim_tga(FILE* fp) { | |
uchar tmp[5]; | |
size_t read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int ext_area_offset=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24); | |
//assert( ext_area_offset >= 0 );//used ! | |
assert(ext_area_offset <= UINT_MAX); | |
read=fread(tmp, 4, 1, fp); | |
assert(read==1); //read 1 * 4 bytes | |
unsigned int dev_area_offset=tmp[0]|((unsigned)tmp[1]<<8)|((unsigned)tmp[2]<<16)|((unsigned)tmp[3]<<24); | |
//assert( dev_area_offset >= 0 );//used ! | |
assert(dev_area_offset <= UINT_MAX); | |
fseek(fp, 0, SEEK_SET); | |
//return to beginning of file | |
return get_file_dim_tga_old(fp); | |
} | |
uint64_t get_file_dim_tga_old(FILE* fp) { | |
uchar tmp[5]; | |
char image_id_length=(char)fgetc(fp);//read 1 byte | |
assert(errno==0); | |
char color_map_type=(char)fgetc(fp);//read 1 byte | |
assert(errno==0); | |
char data_type=(char)fgetc(fp);//read 1 byte (value already checked) | |
assert(errno==0); | |
//3 | |
size_t read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 byte | |
short color_map_origin=(short)(tmp[0]|(unsigned short)tmp[1]<<8); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 byte | |
short color_map_length=(short)(tmp[0]|tmp[1]<<8); | |
char color_map_depth=(char)fgetc(fp);//read 1 byte | |
assert(errno==0); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 byte | |
//3+5=8 | |
short x_origin=(short)(tmp[0]|tmp[1]<<8); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 byte | |
short y_origin=(short)(tmp[0]|tmp[1]<<8); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 byte | |
unsigned short width=(unsigned short)(tmp[0]|(unsigned short)tmp[1]<<8); | |
read=fread(tmp, 2, 1, fp); | |
assert(read==1); //read 1 * 2 byte | |
unsigned short height=(unsigned short)(tmp[0]|(unsigned short)tmp[1]<<8); | |
char bitPerPixel=(char)fgetc(fp);//read 1 byte | |
assert(errno==0); | |
//fprintf(stderr, "[INFO] Bit Per Pixel = %d\n", bitPerPixel); | |
char imageDescriptor=(char)fgetc(fp);//read 1 byte | |
assert(errno==0); | |
//3+5+10=18 | |
//fprintf(stderr, "[INFO] ftell = %ld\n", ftell(fp)); | |
assert(ftell(fp)==18); //reading size check | |
//unused bypass start | |
assert(image_id_length+color_map_type+data_type + | |
color_map_origin+color_map_length+color_map_depth + | |
x_origin+y_origin+width+height+bitPerPixel+imageDescriptor >= 0); | |
//you must be VERY unlucky if this happens, go talk to Murphy. | |
//unused bypass end | |
return ((uint64_t)width<<32|(uint64_t)height); | |
} | |
// |
This file contains hidden or 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
#ifndef FAST_IMAGE_SIZE_READER_HPP | |
#define FAST_IMAGE_SIZE_READER_HPP | |
#include <cstdio> | |
#include <cstring> | |
#include <cassert> | |
#include <inttypes.h> | |
#include "crc32.hpp" | |
enum file_type { | |
UNKNOWN=0, | |
PNG=1, | |
JPG=2, | |
BMP=4, | |
GIF=8, | |
TIF=16, | |
TGA=32, | |
TGA_OLD=64 | |
}; | |
enum file_type get_file_type(const char* filename); | |
uint64_t get_file_dim(const char* filename); | |
uint64_t get_file_dim2(const char* filename, enum file_type ft); | |
uint64_t get_file_dim_png(FILE* fp); | |
uint64_t get_file_dim_jpg(FILE* fp); | |
uint64_t get_file_dim_bmp(FILE* fp); | |
uint64_t get_file_dim_gif(FILE* fp); | |
uint64_t get_file_dim_tif(FILE* fp); | |
uint64_t get_file_dim_tga(FILE* fp); | |
uint64_t get_file_dim_tga_old(FILE* fp); | |
#endif /*FAST_IMAGE_SIZE_READER_HPP*/ | |
// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment