⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readpnm.c

📁 zgv-5.6,一个Linux系统下的图片浏览器(VGA/SVGA)
💻 C
字号:
/* Zgv v5.1 - GIF, JPEG and PBM/PGM/PPM viewer, for VGA PCs running Linux. * Copyright (C) 1993-2000 Russell Marks. See README for license details. * * readpnm.c - PBM/PGM/PPM loader. *             PBM/PGM are loaded as 8-bit, PPM as 24-bit. *             if 8-bit display, PPM is dithered. *             xv 3:3:2 thumbnails also. */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include "zgv.h"#include "rcfile.h"#include "rc_config.h"#include "readpnm.h"/* redefine CLOSE_AND_RET to use closefunc (either fclose or pclose) */#undef CLOSE_AND_RET#define CLOSE_AND_RET(x)	do { closefunc(in); return(x); } while(0)/* for aborted_file_pnm_cleanup() */static unsigned char *work_bmap,*work_pal;static FILE *work_in;static int (*work_closefunc)(FILE *);/* for dither routine */static int *evenerr=NULL,*odderr=NULL;static unsigned char *dbuf=NULL;/* prototypes */void ditch_line(FILE *in);int read_next_number(FILE *in);void aborted_file_pnm_cleanup(void);int ditherinit(int w);void ditherfinish(void);void ditherline(unsigned char *theline, int linenum, int width);int read_xv332(char *filename, unsigned char **bmap, int *width, int *height);void make_332_palette(unsigned char *palptr);/* this works in a slightly confusing way so that the main PNM * reading code can be used for reading from a filter run with popen(), * e.g. tifftopnm. *//* output_type returns how many bytes per pixel needed for display */int read_pnm_file(char *filename,hffunc howfarfunc,unsigned char **bmap,                  unsigned char **pal,int *output_type,PICINFO *pp){FILE *in;*bmap=NULL;*pal=NULL;if((in=fopen(filename,"rb"))==NULL)  return(_PICERR_NOFILE);return(read_pnm_main(in,howfarfunc,bmap,pal,output_type,pp,fclose));}int read_pnm_main(FILE *in,hffunc howfarfunc,unsigned char **bmap,                  unsigned char **pal,int *output_type,PICINFO *pp,                  int (*closefunc)(FILE *)){int c,sub,raw,w,h,maxval,bytepp,x,y,i,n,red,grn,blu,max_is_big;unsigned char *ptr;*bmap=NULL;*pal=NULL;c=fgetc(in);if(c!='P')  CLOSE_AND_RET(_PICERR_BADMAGIC);sub=fgetc(in)-48;if(sub<1 || sub>6)  CLOSE_AND_RET(_PICERR_BADMAGIC);fgetc(in);raw=0;if(sub>3)  {  raw=1;  sub-=3;  }bytepp=(sub==3)?3:1;if((*pal=calloc(768,1))==NULL)  CLOSE_AND_RET(_PICERR_NOMEM);else  {  ptr=*pal;  switch(sub)    {    case 3:      /* only actually used if using 8-bit display, but defined always */      make_332_palette(ptr);      break;    case 2:      for(x=0;x<256;x++,ptr++)        *ptr=ptr[256]=ptr[512]=x;      break;    case 1:      ptr[0]=ptr[256]=ptr[512]=0;      ptr[1]=ptr[257]=ptr[513]=255;    }  }w=read_next_number(in);h=read_next_number(in);if(w==0 || h==0)  CLOSE_AND_RET(_PICERR_CORRUPT);if(sub==1)  maxval=1;else  if((maxval=read_next_number(in))==0)    CLOSE_AND_RET(_PICERR_CORRUPT);max_is_big=(maxval>255);if(sub==3 && (*output_type==1 || cfg.jpeg24bit==0))	/* dither PPM? */  {  bytepp=1;  if(ditherinit(w)==0)    CLOSE_AND_RET(_PICERR_NOMEM);  }if(sub==2 && cfg.betterpgm && cfg.jpeg24bit && (*output_type)==3)  bytepp=3;	/* grind it to 24-bit *//* we allocate two blank lines at the end. reason is the dithering * of PPM files to 8-bit works a line at a time, and we need * 3 times as much for each line, which works out only meaning * 3x as much for the last line. If you see what I mean. (!?) */if((*bmap=malloc(w*(h+2)*bytepp))==NULL)  CLOSE_AND_RET(_PICERR_NOMEM);ptr=*bmap;/* save stuff in case of abort */work_in=in; work_bmap=ptr; work_pal=*pal;work_closefunc=closefunc;/* finally!, we get to read in the image *//* no errors are detected once we start reading. */for(y=0;y<h;y++)  {  for(x=0;x<w;x++)    {    if(raw)      {      switch(sub)        {        case 1: /* PBM */          c=fgetc(in);          for(i=0,n=128;i<8 && x+i<w;i++,n>>=1)            *ptr++=(c&n)?0:1;          x+=7;          break;        case 2: /* PGM */          if(max_is_big)            c=(fgetc(in)<<8),*ptr++=((c|fgetc(in))*255)/maxval;	/* 16-bit */          else            *ptr++=(fgetc(in)*255)/maxval;			/* 8-bit */          break;        case 3: /* PPM */          if(max_is_big)            {            c=(fgetc(in)<<8),red=((c|fgetc(in))*255)/maxval;            c=(fgetc(in)<<8),grn=((c|fgetc(in))*255)/maxval;            c=(fgetc(in)<<8),blu=((c|fgetc(in))*255)/maxval;            }          else            {            red=(fgetc(in)*255)/maxval;            grn=(fgetc(in)*255)/maxval;            blu=(fgetc(in)*255)/maxval;            }                    *ptr++=blu; *ptr++=grn; *ptr++=red;        }      }    else      {      switch(sub)        {        case 1:          do            if((c=fgetc(in))=='#') ditch_line(in);          while(c!='0' && c!='1');          *ptr++=(c=='1')?0:1;          break;        case 2:          *ptr++=(read_next_number(in)*255)/maxval;          break;        case 3:          red=(read_next_number(in)*255)/maxval;          grn=(read_next_number(in)*255)/maxval;          blu=(read_next_number(in)*255)/maxval;          *ptr++=blu; *ptr++=grn; *ptr++=red;        }      }		/* end of 'if(raw)' */    /* if PGM and bytepp=3, but have cfg.betterpgm set */    if(sub==2 && bytepp==3)      {      c=ptr[-1];      *ptr++=c; *ptr++=c;      }    }  /* if PPM and 8-bit display, dither now */  if(sub==3 && bytepp==1)    {    ptr-=w*3;    ditherline(ptr,y,w);    ptr+=w;    }      if(howfarfunc!=NULL) howfarfunc(y,h);  }pp->width=w;pp->height=h;pp->numcols=(sub==1)?2:256;*output_type=bytepp;if(sub==3 && bytepp==1)  ditherfinish();  closefunc(in);return(_PIC_OK);  }void ditch_line(FILE *in){int c;while((c=fgetc(in))!='\n' && c!=EOF);}/* for text-style PNM files, i.e. P[123]. * we take an extremely generous outlook - anything other than a decimal * digit is considered whitespace. * and as per p[bgp]m(5), comments can start anywhere. */int read_next_number(FILE *in){int c,num,in_num,gotnum;num=0;in_num=gotnum=0;do  {  if(feof(in)) return(0);  if((c=fgetc(in))=='#')    ditch_line(in);  else    if(isdigit(c))      num=10*num+c-49+(in_num=1);    else      gotnum=in_num;  }while(!gotnum);  return(num);}void aborted_file_pnm_cleanup(){free(work_bmap);free(work_pal);work_closefunc(work_in);}int ditherinit(int w){ditherfinish();		/* make sure any previous mem is unallocated */if((evenerr=calloc(3*(w+10),sizeof(int)))==NULL ||   (odderr =calloc(3*(w+10),sizeof(int)))==NULL ||   (dbuf   =malloc(w))==NULL)  return(0);else  return(1);}void ditherfinish(){if(evenerr!=NULL) { free(evenerr); evenerr=NULL; }if(odderr!=NULL)  { free(odderr);  odderr=NULL; }if(dbuf!=NULL)    { free(dbuf);    dbuf=NULL; }}void ditherline(unsigned char *theline,int linenum,int width){int x,y,lx;int c0,c1,c2,times2;int terr0,terr1,terr2,actual0,actual1,actual2;int start,addon,r,g,b;int *thiserr;int *nexterr;y=linenum;if((y&1)==0)  {start=0; addon=1;  thiserr=evenerr+3; nexterr=odderr+width*3;}else  {start=width-1; addon=-1;  thiserr=odderr+3; nexterr=evenerr+width*3;}nexterr[0]=nexterr[1]=nexterr[2]=0;x=start;for(lx=0;lx<width;lx++)  {  b=theline[x*3];  g=theline[x*3+1];  r=theline[x*3+2];  terr0=r+((thiserr[0]+8)>>4);  terr1=g+((thiserr[1]+8)>>4);  terr2=b+((thiserr[2]+8)>>4);  /* is this going to screw up on white? */    actual0=(terr0>>5)*255/7;  actual1=(terr1>>5)*255/7;  actual2=(terr2>>6)*255/3;    if(actual0<0) actual0=0; if(actual0>255) actual0=255;  if(actual1<0) actual1=0; if(actual1>255) actual1=255;  if(actual2<0) actual2=0; if(actual2>255) actual2=255;    c0=terr0-actual0;  c1=terr1-actual1;  c2=terr2-actual2;  times2=(c0<<1);  nexterr[-3] =c0; c0+=times2;  nexterr[ 3]+=c0; c0+=times2;  nexterr[ 0]+=c0; c0+=times2;  thiserr[ 3]+=c0;  times2=(c1<<1);  nexterr[-2] =c1; c1+=times2;  nexterr[ 4]+=c1; c1+=times2;  nexterr[ 1]+=c1; c1+=times2;  thiserr[ 4]+=c1;  times2=(c2<<1);  nexterr[-1] =c2; c2+=times2;  nexterr[ 5]+=c2; c2+=times2;  nexterr[ 2]+=c2; c2+=times2;  thiserr[ 5]+=c2;  dbuf[x]=(actual0>>5)*32+(actual1>>5)*4+(actual2>>6);  thiserr+=3;  nexterr-=3;  x+=addon;  }memcpy(theline,dbuf,width);}/* xv 3:3:2 thumbnail files - these are similar to pgm raw files, * but the context in which they are used is very different; as such * we have a separate routine for loading them. * they seem to have a max. size of 80x60. */int read_xv332(char *filename,unsigned char **bmap,int *width,int *height){FILE *in;char buf[128];int w,h,maxval;int count;*bmap=NULL; *width=0; *height=0;if((in=fopen(filename,"rb"))==NULL)  return(_PICERR_NOFILE);fgets(buf,sizeof(buf),in);if(strcmp(buf,"P7 332\n")!=0)  return(_PICERR_BADMAGIC);/* we're not worried about any comments */w=read_next_number(in);h=read_next_number(in);*width=w; *height=h;if(w==0 || h==0 || w>80 || h>60)  return(_PICERR_CORRUPT);/* for some reason, they have a maxval...!? * we complain if it's not 255. */if((maxval=read_next_number(in))!=255)  return(_PICERR_CORRUPT);if((*bmap=malloc(w*h))==NULL)  return(_PICERR_NOMEM);count=fread(*bmap,1,w*h,in);if(count!=w*h)  return(_PICERR_CORRUPT);fclose(in);return(_PIC_OK);  }void make_332_palette(unsigned char *palptr){int r,g,b;for(r=0;r<8;r++)  for(g=0;g<8;g++)	/* colours are 3:3:2 */    for(b=0;b<4;b++)      {      *palptr=r*255/7; palptr[256]=g*255/7; palptr[512]=b*255/3;      palptr++;      }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -