📄 pbm2png.c
字号:
/* (c) 2000 Karel Kulhavy, Clocksoft * clock@atrey.karlin.mff.cuni.cz * This program is a stdin filter that performs these operations: * 1) Downconverts 17x15 oversampled binary image data (black-or-white * pixels, 1 bit per pixel, pbmraw format) to 256-level grayscale * pgmraw format and saves it to basename_%d.png. * 2) At the end, generates necessary html's * 3) The input pages must be concatenated * 4) Recommended source of the pbm: Aladdin Ghostscript * If there is an input argument (one number as first arg), it's treated * as number of first page that comes at fd #0. Default value is 0. * Parameters: <hundred_dpi> <basename_> <titlestring> <bottom_html_code> * <pageoffset> <input_filename> [first page number] * Little benchmarks: Normal (gs+pbm2png) 1:32 Without pbm2png 0:28 Without libpng 0:51 Without grayscaling 0:32 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <png.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>unsigned char *basename_;/* basename: pbm2png.c:32: `basename' redeclared as different kind of symbol /usr/include/string.h:245: previous declaration of `basename'*/unsigned char *titlestring;unsigned char *bottom;int pageoffset=-13;unsigned long t1[256]; /* Conversion from 1-bit to 2-bit expansion */unsigned long t2[256]; /* Conversion from 2-bit to 4-bit expansion */unsigned char *l1; /* Input data, output data. lw<<1 bytes long */unsigned long *l2; /* 2-bit expansion lw unsigned long's long*/unsigned long long *l4; /* 4-bit expansion lw unsigned long long's long */int ox,oy;int lw; /* Width of the input in 16-pixel units. */int lb; /* Width of the input in 8-pixel units */FILE *of;int filenumber;int x,y;png_structp png_ptr;png_infop info_ptr;unsigned long ppm;float dpi;unsigned char string[8192];unsigned char *filename;int ifd;voidgentables(void){ int a,d; unsigned long b; unsigned char c; for (a=0;a<256;a++){ b=0; c=a; for (d=7;d>=0;d--){ b<<=2; b|=(c>>d)&1; } t1[a]=b; b=0; c=a; for (d=4;d;d--){ b<<=4; b|=c&3; c>>=2; } t2[a]=b; }}voidmake_index(void){ FILE *f; f=fopen("index.html","w"); fprintf(f,"<html><head><title>%s</title></head><body bgcolor=\"#000000\" text=\"#00ff00\" link=\"#ffff00\"" " vlink=\"#00ffff\" alink=\"#ffff00\">\n",titlestring); fprintf(f,"<a href=\"../\"><img src=\"up.png\" border=0></a><br>" "<a href=\"%s.pdf\">Download in PDF format</a><br>" "<h1>%s</h1><h2>Page index</h2>",basename_,titlestring); { int n; unsigned char *t; FILE *g; fprintf(f,"<table cellspacing=0 cellpadding=0 border=1>\n<tr>"); for (n=0;n<filenumber;n++){ if (!(n%40)&&n){ fprintf(f,"</tr>\n<tr>"); } fprintf(f,"<td><a href=\"%s%d.html\">%d</a></td>\n",basename_,n,n+pageoffset); } fprintf(f,"</tr></table><h2>"); g=fopen("index.dir","rb"); if (g) { t=malloc(65536); fprintf(f,"Contents Index</h2><table border=0 cellspacing=0 cellpadding=0>"); while(fgets(t,65536,g)){ int val=0; int len=strlen(t); unsigned char *u=t; if (len&&t[len-1]=='\n') t[len-1]=0; if (*t>'9'||*t<'0') continue; while(*u>='0'&&*u<='9'){ val*=10; val+=*u-'0'; u++; } val--; u++; /* The char behind the number is ignored */ fprintf(f,"<tr><td>%d </td><td><a href=\"%s%d.html\">%s</a></td></tr>\n",val+pageoffset ,basename_,val,u); } fprintf(f,"</table>"); fclose(g); free(t); } fprintf(f,"</body></html>"); fclose(f); }}voidmake_page(int index){ FILE *f; sprintf(string,"%s%d.html",basename_,index); f=fopen(string,"w"); fprintf(f,"<html><head><title>%s</title></head><body bgcolor=\"#000000\" text=\"#00ff00\" link=\"#ffff00\" vlink=\"#00ffff\"alink=\"#ffff00\">\n",titlestring); fprintf(f,"<h1>%s, Page %d</h1>\n",titlestring,index+pageoffset); fprintf(f,"<p><table border=0 cellspacing=0 cellpadding=2><tr>"); fprintf(f,"<td valign=\"top\"><table border=0 cellpadding=0 cellspacing=0><tr><td>"); if (index) { fprintf(f,"<a href=\"%s%d.html\"><img src=\"left.png\" border=0></a>\n",basename_,index-1); } else { fprintf(f,"<img src=\"left.png\" border=0>\n"); } fprintf(f,"</td><td>"); if (index<filenumber-1) { fprintf(f,"<a href=\"%s%d.html\"><img src=\"right.png\" border=0></a>\n",basename_,index+1); } else { fprintf(f,"<img src=\"right.png\" border=0>\n"); } fprintf(f,"</td></tr><tr><td colspan=2><a href=\"index.html\"><img src=\"idx.png\" border=0 ></a></td>"); fprintf(f,"</tr></table>"); fprintf(f,"</td><td><img src=\"%s%d.png\" border=\"0\"></td>\n</tr></table>",basename_,index); fprintf(f,"</body></html>"); fclose(f);}/* Returns 0 is OK, exit(1) on error, returns 1 on broken pipe */int sure_read(unsigned char *dest, size_t len){ ssize_t rd; if (!len) return 0; again: rd=read(ifd,dest,len); if (rd==len) return 0; if (!rd) return 1; if (rd<0&&(errno==EINTR||errno==EAGAIN||errno==EWOULDBLOCK)) goto again; if (rd>0&&rd<len){ /*fprintf(stderr,"read %d/%d",rd,len);*/ len-=rd; dest+=rd; fflush(stderr); goto again; } fprintf(stderr,"read error.\n"); perror(""); exit(1);}inteat_up_whitespace_and_comments(void){ again: sure_read(string,1); if (*string==' '||*string=='\t'){ goto again; } if (*string=='\n'||*string=='\r'){ goto again; } if (*string=='#'){ /* Eat up comment */ aa: sure_read(string,1); if (*string!='\n'&&*string!='\r') goto aa; goto again; } return *string;}intread_header(void){ /* if (filenumber) { int a; for (a=0;a<256;a++){ sure_read(string,1); printf("%d ", *string); fflush(stdout); } exit(0); } */ if (sure_read(string,2)) return 1; /* P1 */ x=eat_up_whitespace_and_comments()-'0'; again: sure_read(string,1); if (*string!=' '&&*string!='\t'&&*string!='\n'&&*string!='\r'){ x*=10; x+=*string-'0'; goto again; } y=eat_up_whitespace_and_comments()-'0'; bgain: sure_read(string,1); if (*string!=' '&&*string!='\t'&&*string!='\n'&&*string!='\r'){ y*=10; y+=*string-'0'; goto bgain; } return 0;}voidopen_png(void){ png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); info_ptr=png_create_info_struct(png_ptr); png_init_io(png_ptr,of); png_set_filter(png_ptr,0,PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_UP |PNG_FILTER_AVG|PNG_FILTER_PAETH); png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); png_set_IHDR(png_ptr,info_ptr,ox,oy,8,PNG_COLOR_TYPE_GRAY,PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); png_set_gAMA(png_ptr,info_ptr,1.0); png_set_pHYs(png_ptr,info_ptr,ppm,ppm,PNG_RESOLUTION_METER); png_write_info(png_ptr,info_ptr);}voidclose_png(void){ png_write_end(png_ptr,info_ptr); png_destroy_write_struct(&png_ptr,&info_ptr);}/* Represents the same pixels that are in l2 in l4. */voidmove_2_to_4(void){ unsigned long long bit4; unsigned long bit2; int index; for (index=lw-1;index>=0;index--){ bit2=l2[index]; bit4=t2[bit2&255]; bit4<<=16; bit2>>=8; bit4|=t2[bit2&255]; bit4<<=16; bit2>>=8; bit4|=t2[bit2&255]; bit4<<=16; bit2>>=8; bit4|=t2[bit2&255]; l4[index]=bit4; }}/* Adds the same pixels that are in l2 to l4. */voidadd_2_to_4(void){ unsigned long long bit4; unsigned long bit2; int index; for (index=lw-1;index>=0;index--){ bit2=l2[index]; bit4=t2[bit2&255]; bit4<<=16; bit2>>=8; bit4|=t2[bit2&255]; bit4<<=16; bit2>>=8; bit4|=t2[bit2&255]; bit4<<=16; bit2>>=8; bit4|=t2[bit2&255]; l4[index]+=bit4; }}/* Moves pixels from l1 to l2 with format change */voidmove_1_to_2(void){ int index; for (index=lw-1;index>=0;index--) l2[index]=(t1[l1[index<<1]]<<16)|t1[l1[(index<<1)+1]];}/* Adds pixels from l1 to l2 with format change */voidadd_1_to_2(void){ int index; for (index=lw-1;index>=0;index--) l2[index]+=(t1[l1[index<<1]]<<16)|t1[l1[(index<<1)+1]];}/* Loads 1 line into l1 */voidload(void){ sure_read(l1,lb);}/* Loads 3 lines into l2 */voidload_to_2(void){ load(); move_1_to_2(); load(); add_1_to_2(); load(); add_1_to_2(); }/* Loads 15 lines into l4 */voidload_to_4(void){ load_to_2(); move_2_to_4(); load_to_2(); add_2_to_4(); load_to_2(); add_2_to_4(); load_to_2(); add_2_to_4(); load_to_2(); add_2_to_4();}/* Converts the data from l4 to l1 including suming up 17 adjacent pixels */voidexport_from_4(void){ int a,b,reg_hold; unsigned char sum; unsigned long long *loader=l4; unsigned long long reg=0; reg_hold=0; for (a=0;a<ox;a++){ sum=0; for (b=17;b;b--){ if (!reg_hold){ reg=*loader++; reg_hold=16; } sum+=reg&15; reg>>=4; reg_hold--; } l1[a]=sum; } png_write_row(png_ptr,l1);}/* * Parameters: <hundred_dpi> <basename_> <titlestring> <bottom_html_code> * <pageoffset> [first page number] */intmain(int argc, char **argv){ int a,z; if (argc<7){ fprintf(stderr,"Usage: pbm2png <hundred_dpi> <basename_> <titlestring><bottom_html_code> <pageoffset> <ifname> [starting_filenumber]\n"); return 0; } dpi=atof(argv[1])/10; ppm=dpi*1000/25.4; basename_=argv[2]; titlestring=argv[3]; bottom=argv[4]; pageoffset=atol(argv[5]); filename=argv[6]; again0: ifd=open(filename,O_RDONLY); if (ifd<0){ if (errno==EAGAIN||errno==EINTR||errno==EWOULDBLOCK) goto again0; else { perror(""); exit(1); } } fprintf(stderr,"filename %s, %d\n",filename,ifd); if (argc>=8){ filenumber=atol(argv[7]); } gentables(); again: fprintf(stderr,"\nFile %i\n",filenumber); if (read_header()){ for (a=0;a<filenumber;a++) make_page(a); make_index(); return 0; } lw=(x+15)>>4; lb=(x+7)>>3; ox=x/17; oy=y/15; fprintf(stderr,"Input: %i*%i pixels, %f*%f dpi, %.1fMB.\n",x,y,dpi*17,dpi*15,(float)lb*y/1048576); fprintf(stderr,"Ouput: %i*%i pixels, %f*%f dpi, %.1fKB raw data.\n",ox,oy,dpi,dpi,(float)ox*oy/1024); l1=(unsigned char*)malloc(lw*2); l2=(unsigned long*)malloc(lw*sizeof(unsigned long)); l4=(unsigned long long*)malloc(lw*sizeof(unsigned long long)); sprintf(string,"%s%d.png",basename_,filenumber); filenumber++; of=fopen(string,"w"); open_png(); for (z=oy;z;z--){ if (!(z&15)){ fprintf(stderr,"."); fflush(stderr); } load_to_4(); export_from_4(); } close_png(); fprintf(stderr,"\nWritten %lu bytes of data, ratio %.1f%%\n",ftell(of),(float)ftell(of)*100/ox/oy); fclose(of); for (a=y%15;a;a--) load(); free(l1); free(l2); free(l4); goto again;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -