KiCad PCB EDA Suite
greymap.cpp File Reference
#include <errno.h>
#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "bitops.h"
#include "greymap.h"

Go to the source code of this file.

Classes

struct  bmp_info_s
 

Macros

#define INTBITS   ( 8 * sizeof( int ) )
 
#define mod(a, n)   ( ( a ) >= ( n ) ? ( a ) % ( n ) : ( a ) >= 0 ? ( a ) : (n) - 1 - ( -1 - ( a ) ) % ( n ) )
 
#define TRY(x)
 
#define TRY_EOF(x)
 
#define TRY_STD(x)
 
#define COLTABLE(c)   ( ( c ) < bmpinfo.ncolors ? coltable[( c )] : 0 )
 

Typedefs

typedef struct bmp_info_s bmp_info_t
 

Functions

static int gm_readbody_pnm (FILE *f, greymap_t **gmp, int magic)
 
static int gm_readbody_bmp (FILE *f, greymap_t **gmp)
 
static ptrdiff_t getsize (int dy, int h)
 
static ptrdiff_t gm_size (const greymap_t *gm)
 
greymap_tgm_new (int w, int h)
 
void gm_free (greymap_t *gm)
 
greymap_tgm_dup (greymap_t *gm)
 
void gm_clear (greymap_t *gm, int b)
 
static void gm_flip (greymap_t *gm)
 
static int gm_resize (greymap_t *gm, int h)
 
static int fgetc_ws (FILE *f)
 
static int readnum (FILE *f)
 
static int readbit (FILE *f)
 
int gm_read (FILE *f, greymap_t **gmp)
 
static int bmp_readint (FILE *f, int n, unsigned int *p)
 
static void bmp_pad_reset (void)
 
static int bmp_pad (FILE *f)
 
static int bmp_forward (FILE *f, int pos)
 
int gm_writepgm (FILE *f, greymap_t *gm, const char *comment, int raw, int mode, double gamma)
 
int gm_print (FILE *f, greymap_t *gm)
 

Variables

const char * gm_read_error = NULL
 
static int bmp_count = 0
 
static int bmp_pos = 0
 

Macro Definition Documentation

#define COLTABLE (   c)    ( ( c ) < bmpinfo.ncolors ? coltable[( c )] : 0 )

Definition at line 825 of file greymap.cpp.

Referenced by gm_readbody_bmp().

#define INTBITS   ( 8 * sizeof( int ) )

Definition at line 22 of file greymap.cpp.

Referenced by gm_readbody_bmp().

#define TRY (   x)
Value:
if( x ) \
goto try_error

Definition at line 30 of file greymap.cpp.

Referenced by gm_readbody_bmp().

#define TRY_EOF (   x)
Value:
if( x ) \
goto eof

Definition at line 33 of file greymap.cpp.

Referenced by gm_readbody_bmp().

#define TRY_STD (   x)
Value:
if( x ) \
goto std_error

Definition at line 36 of file greymap.cpp.

Referenced by gm_readbody_bmp(), and gm_readbody_pnm().

Typedef Documentation

typedef struct bmp_info_s bmp_info_t

Definition at line 737 of file greymap.cpp.

Function Documentation

static int bmp_forward ( FILE *  f,
int  pos 
)
static

Definition at line 803 of file greymap.cpp.

References bmp_count, and bmp_pos.

Referenced by gm_readbody_bmp().

804 {
805  int b;
806 
807  while( bmp_pos < pos )
808  {
809  b = fgetc( f );
810 
811  if( b == EOF )
812  {
813  return 1;
814  }
815 
816  bmp_pos++;
817  bmp_count++;
818  }
819 
820  return 0;
821 }
static int bmp_count
Definition: greymap.cpp:741
static int bmp_pos
Definition: greymap.cpp:742
static int bmp_pad ( FILE *  f)
static

Definition at line 780 of file greymap.cpp.

References bmp_count, and bmp_pos.

Referenced by gm_readbody_bmp().

781 {
782  int c, i, b;
783 
784  c = ( -bmp_count ) & 3;
785 
786  for( i = 0; i < c; i++ )
787  {
788  b = fgetc( f );
789 
790  if( b == EOF )
791  {
792  return 1;
793  }
794  }
795 
796  bmp_pos += c;
797  bmp_count = 0;
798  return 0;
799 }
static int bmp_count
Definition: greymap.cpp:741
static int bmp_pos
Definition: greymap.cpp:742
static void bmp_pad_reset ( void  )
static

Definition at line 772 of file greymap.cpp.

References bmp_count.

Referenced by gm_readbody_bmp().

773 {
774  bmp_count = 0;
775 }
static int bmp_count
Definition: greymap.cpp:741
static int bmp_readint ( FILE *  f,
int  n,
unsigned int *  p 
)
static

Definition at line 746 of file greymap.cpp.

References bmp_count, and bmp_pos.

Referenced by gm_readbody_bmp().

747 {
748  int i;
749  unsigned int sum = 0;
750  int b;
751 
752  for( i = 0; i < n; i++ )
753  {
754  b = fgetc( f );
755 
756  if( b == EOF )
757  {
758  return 1;
759  }
760 
761  sum += (unsigned) b << ( 8 * i );
762  }
763 
764  bmp_count += n;
765  bmp_pos += n;
766  *p = sum;
767  return 0;
768 }
static int bmp_count
Definition: greymap.cpp:741
static int bmp_pos
Definition: greymap.cpp:742
static int fgetc_ws ( FILE *  f)
static

Definition at line 257 of file greymap.cpp.

Referenced by gm_read(), readbit(), and readnum().

258 {
259  int c;
260 
261  while( 1 )
262  {
263  c = fgetc( f );
264 
265  if( c == '#' )
266  {
267  while( 1 )
268  {
269  c = fgetc( f );
270 
271  if( c == '\n' || c == EOF )
272  {
273  break;
274  }
275  }
276  }
277 
278  /* space, tab, line feed, carriage return, form-feed */
279  if( c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != 12 )
280  {
281  return c;
282  }
283  }
284 }
static ptrdiff_t getsize ( int  dy,
int  h 
)
inlinestatic

Definition at line 46 of file greymap.cpp.

Referenced by gm_new(), gm_resize(), and gm_size().

47 {
48  ptrdiff_t size;
49 
50  if( dy < 0 )
51  {
52  dy = -dy;
53  }
54 
55  size = (ptrdiff_t) dy * (ptrdiff_t) h * (ptrdiff_t) sizeof( gm_sample_t );
56 
57  /* check for overflow error */
58  if( size < 0 || ( h != 0 && dy != 0 && size / h / dy != sizeof( gm_sample_t ) ) )
59  {
60  return -1;
61  }
62 
63  return size;
64 }
signed short int gm_sample_t
Definition: greymap.h:13
void gm_clear ( greymap_t gm,
int  b 
)

Definition at line 155 of file greymap.cpp.

References greymap_s::base, gm_size(), GM_UPUT, greymap_s::h, and greymap_s::w.

156 {
157  ptrdiff_t size = gm_size( gm );
158  int x, y;
159 
160  if( b == 0 )
161  {
162  memset( gm->base, 0, size );
163  }
164  else
165  {
166  for( y = 0; y < gm->h; y++ )
167  {
168  for( x = 0; x < gm->w; x++ )
169  {
170  GM_UPUT( gm, x, y, b );
171  }
172  }
173  }
174 }
int h
Definition: greymap.h:21
int w
Definition: greymap.h:20
static ptrdiff_t gm_size(const greymap_t *gm)
Definition: greymap.cpp:71
#define GM_UPUT(gm, x, y, b)
Definition: greymap.h:40
gm_sample_t * base
Definition: greymap.h:24
greymap_t* gm_dup ( greymap_t gm)

Definition at line 134 of file greymap.cpp.

References greymap_s::dy, gm_new(), gm_scanline, greymap_s::h, and greymap_s::w.

135 {
136  greymap_t* gm1 = gm_new( gm->w, gm->h );
137  int y;
138 
139  if( !gm1 )
140  {
141  return NULL;
142  }
143 
144  for( y = 0; y < gm->h; y++ )
145  {
146  memcpy( gm_scanline( gm1, y ), gm_scanline( gm, y ),
147  (size_t) gm1->dy * sizeof( gm_sample_t ) );
148  }
149 
150  return gm1;
151 }
int h
Definition: greymap.h:21
#define gm_scanline(gm, y)
Definition: greymap.h:32
int w
Definition: greymap.h:20
greymap_t * gm_new(int w, int h)
Definition: greymap.cpp:79
int dy
Definition: greymap.h:22
signed short int gm_sample_t
Definition: greymap.h:13
static void gm_flip ( greymap_t gm)
inlinestatic

Definition at line 179 of file greymap.cpp.

References greymap_s::dy, gm_scanline, greymap_s::h, and greymap_s::map.

Referenced by gm_readbody_bmp(), gm_readbody_pnm(), and gm_resize().

180 {
181  int dy = gm->dy;
182 
183  if( gm->h == 0 || gm->h == 1 )
184  {
185  return;
186  }
187 
188  gm->map = gm_scanline( gm, gm->h - 1 );
189  gm->dy = -dy;
190 }
int h
Definition: greymap.h:21
#define gm_scanline(gm, y)
Definition: greymap.h:32
gm_sample_t * map
Definition: greymap.h:25
int dy
Definition: greymap.h:22
void gm_free ( greymap_t gm)

Definition at line 122 of file greymap.cpp.

References greymap_s::base.

Referenced by gm_readbody_bmp(), and gm_readbody_pnm().

123 {
124  if( gm )
125  {
126  free( gm->base );
127  }
128 
129  free( gm );
130 }
gm_sample_t * base
Definition: greymap.h:24
greymap_t* gm_new ( int  w,
int  h 
)

Definition at line 79 of file greymap.cpp.

References greymap_s::base, greymap_s::dy, getsize(), greymap_s::h, greymap_s::map, and greymap_s::w.

Referenced by gm_dup(), gm_readbody_bmp(), and gm_readbody_pnm().

80 {
81  greymap_t* gm;
82  int dy = w;
83  ptrdiff_t size;
84 
85  size = getsize( dy, h );
86 
87  if( size < 0 )
88  {
89  errno = ENOMEM;
90  return NULL;
91  }
92 
93  if( size == 0 )
94  {
95  size = 1; /* make surecmalloc() doesn't return NULL */
96  }
97 
98  gm = (greymap_t*) malloc( sizeof( greymap_t ) );
99 
100  if( !gm )
101  {
102  return NULL;
103  }
104 
105  gm->w = w;
106  gm->h = h;
107  gm->dy = dy;
108  gm->base = (gm_sample_t*) calloc( 1, size );
109 
110  if( !gm->base )
111  {
112  free( gm );
113  return NULL;
114  }
115 
116  gm->map = gm->base;
117  return gm;
118 }
int h
Definition: greymap.h:21
static ptrdiff_t getsize(int dy, int h)
Definition: greymap.cpp:46
int w
Definition: greymap.h:20
gm_sample_t * base
Definition: greymap.h:24
gm_sample_t * map
Definition: greymap.h:25
int dy
Definition: greymap.h:22
signed short int gm_sample_t
Definition: greymap.h:13
int gm_print ( FILE *  f,
greymap_t gm 
)

Definition at line 1430 of file greymap.cpp.

References GM_GET, greymap_s::h, and greymap_s::w.

1431 {
1432  int x, y;
1433  int xx, yy;
1434  int d, t;
1435  int sw, sh;
1436 
1437  sw = gm->w < 79 ? gm->w : 79;
1438  sh = gm->w < 79 ? gm->h : gm->h * sw * 44 / ( 79 * gm->w );
1439 
1440  for( yy = sh - 1; yy >= 0; yy-- )
1441  {
1442  for( xx = 0; xx < sw; xx++ )
1443  {
1444  d = 0;
1445  t = 0;
1446 
1447  for( x = xx * gm->w / sw; x < ( xx + 1 ) * gm->w / sw; x++ )
1448  {
1449  for( y = yy * gm->h / sh; y < ( yy + 1 ) * gm->h / sh; y++ )
1450  {
1451  d += GM_GET( gm, x, y );
1452  t += 256;
1453  }
1454  }
1455 
1456  fputc( "*#=- "[5 * d / t], f ); /* what a cute trick :) */
1457  }
1458 
1459  fputc( '\n', f );
1460  }
1461 
1462  return 0;
1463 }
int h
Definition: greymap.h:21
int w
Definition: greymap.h:20
#define GM_GET(gm, x, y)
Definition: greymap.h:41
int gm_read ( FILE *  f,
greymap_t **  gmp 
)

Definition at line 378 of file greymap.cpp.

References fgetc_ws(), gm_readbody_bmp(), and gm_readbody_pnm().

379 {
380  int magic[2];
381 
382  /* read magic number. We ignore whitespace and comments before the
383  * magic, for the benefit of concatenated files in P1-P3 format.
384  * Multiple P1-P3 images in a single file are not formally allowed
385  * by the PNM standard, but there is no harm in being lenient. */
386 
387  magic[0] = fgetc_ws( f );
388 
389  if( magic[0] == EOF )
390  {
391  /* files which contain only comments and whitespace count as "empty" */
392  return -3;
393  }
394 
395  magic[1] = fgetc( f );
396 
397  if( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' )
398  {
399  return gm_readbody_pnm( f, gmp, magic[1] );
400  }
401 
402  if( magic[0] == 'B' && magic[1] == 'M' )
403  {
404  return gm_readbody_bmp( f, gmp );
405  }
406 
407  return -4;
408 }
static int gm_readbody_bmp(FILE *f, greymap_t **gmp)
Definition: greymap.cpp:834
static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic)
Definition: greymap.cpp:415
static int fgetc_ws(FILE *f)
Definition: greymap.cpp:257
static int gm_readbody_bmp ( FILE *  f,
greymap_t **  gmp 
)
static

Definition at line 834 of file greymap.cpp.

References bmp_info_s::AlphaMask, bmp_info_s::bits, bmp_info_s::BlueMask, bmp_forward(), bmp_pad(), bmp_pad_reset(), bmp_pos, bmp_readint(), bmp_info_s::ColorsImportant, COLTABLE, bmp_info_s::comp, bmp_info_s::ctbits, bmp_info_s::DataOffset, bmp_info_s::FileSize, gm_flip(), gm_free(), gm_new(), GM_PUT, gm_read_error, gm_resize(), GM_UPUT, bmp_info_s::GreenMask, bmp_info_s::h, bmp_info_s::ImageSize, bmp_info_s::InfoSize, INTBITS, lobit(), bmp_info_s::ncolors, bmp_info_s::Planes, bmp_info_s::RedMask, bmp_info_s::reserved, bmp_info_s::topdown, TRY, TRY_EOF, TRY_STD, bmp_info_s::w, bmp_info_s::XpixelsPerM, and bmp_info_s::YpixelsPerM.

Referenced by gm_read().

835 {
836  bmp_info_t bmpinfo;
837  int* coltable;
838  unsigned int b, c;
839  unsigned int i, j;
840  greymap_t* gm;
841  unsigned int x, y;
842  int col[2];
843  unsigned int bitbuf;
844  unsigned int n;
845  unsigned int redshift, greenshift, blueshift;
846  int realheight; /* in case of incomplete file, keeps track of how
847  * many scan lines actually contain data */
848 
849  gm_read_error = NULL;
850  gm = NULL;
851  coltable = NULL;
852 
853  bmp_pos = 2; /* set file position */
854 
855  /* file header (minus magic number) */
856  TRY( bmp_readint( f, 4, &bmpinfo.FileSize ) );
857  TRY( bmp_readint( f, 4, &bmpinfo.reserved ) );
858  TRY( bmp_readint( f, 4, &bmpinfo.DataOffset ) );
859 
860  /* info header */
861  TRY( bmp_readint( f, 4, &bmpinfo.InfoSize ) );
862 
863  if( bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64 || bmpinfo.InfoSize == 108
864  || bmpinfo.InfoSize == 124 )
865  {
866  /* Windows or new OS/2 format */
867  bmpinfo.ctbits = 32; /* sample size in color table */
868  TRY( bmp_readint( f, 4, &bmpinfo.w ) );
869  TRY( bmp_readint( f, 4, &bmpinfo.h ) );
870  TRY( bmp_readint( f, 2, &bmpinfo.Planes ) );
871  TRY( bmp_readint( f, 2, &bmpinfo.bits ) );
872  TRY( bmp_readint( f, 4, &bmpinfo.comp ) );
873  TRY( bmp_readint( f, 4, &bmpinfo.ImageSize ) );
874  TRY( bmp_readint( f, 4, &bmpinfo.XpixelsPerM ) );
875  TRY( bmp_readint( f, 4, &bmpinfo.YpixelsPerM ) );
876  TRY( bmp_readint( f, 4, &bmpinfo.ncolors ) );
877  TRY( bmp_readint( f, 4, &bmpinfo.ColorsImportant ) );
878 
879  if( bmpinfo.InfoSize >= 108 )
880  {
881  /* V4 and V5 bitmaps */
882  TRY( bmp_readint( f, 4, &bmpinfo.RedMask ) );
883  TRY( bmp_readint( f, 4, &bmpinfo.GreenMask ) );
884  TRY( bmp_readint( f, 4, &bmpinfo.BlueMask ) );
885  TRY( bmp_readint( f, 4, &bmpinfo.AlphaMask ) );
886  }
887 
888  if( bmpinfo.w > 0x7fffffff )
889  {
890  goto format_error;
891  }
892 
893  if( bmpinfo.h > 0x7fffffff )
894  {
895  bmpinfo.h = ( -bmpinfo.h ) & 0xffffffff;
896  bmpinfo.topdown = 1;
897  }
898  else
899  {
900  bmpinfo.topdown = 0;
901  }
902 
903  if( bmpinfo.h > 0x7fffffff )
904  {
905  goto format_error;
906  }
907  }
908  else if( bmpinfo.InfoSize == 12 )
909  {
910  /* old OS/2 format */
911  bmpinfo.ctbits = 24; /* sample size in color table */
912  TRY( bmp_readint( f, 2, &bmpinfo.w ) );
913  TRY( bmp_readint( f, 2, &bmpinfo.h ) );
914  TRY( bmp_readint( f, 2, &bmpinfo.Planes ) );
915  TRY( bmp_readint( f, 2, &bmpinfo.bits ) );
916  bmpinfo.comp = 0;
917  bmpinfo.ncolors = 0;
918  bmpinfo.topdown = 0;
919  }
920  else
921  {
922  goto format_error;
923  }
924 
925  if( bmpinfo.comp == 3 && bmpinfo.InfoSize < 108 )
926  {
927  /* bitfield feature is only understood with V4 and V5 format */
928  goto format_error;
929  }
930 
931  if( bmpinfo.comp > 3 || bmpinfo.bits > 32 )
932  {
933  goto format_error;
934  }
935 
936  /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
937  TRY( bmp_forward( f, 14 + bmpinfo.InfoSize ) );
938 
939  if( bmpinfo.Planes != 1 )
940  {
941  gm_read_error = "cannot handle bmp planes";
942  goto format_error; /* can't handle planes */
943  }
944 
945  if( bmpinfo.ncolors == 0 && bmpinfo.bits <= 8 )
946  {
947  bmpinfo.ncolors = 1 << bmpinfo.bits;
948  }
949 
950  /* color table, present only if bmpinfo.bits <= 8. */
951  if( bmpinfo.bits <= 8 )
952  {
953  coltable = (int*) calloc( bmpinfo.ncolors, sizeof( int ) );
954 
955  if( !coltable )
956  {
957  goto std_error;
958  }
959 
960  /* NOTE: since we are reading a greymap, we can immediately convert
961  * the color table entries to grey values. */
962  for( i = 0; i < bmpinfo.ncolors; i++ )
963  {
964  TRY( bmp_readint( f, bmpinfo.ctbits / 8, &c ) );
965  c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff );
966  coltable[i] = c / 3;
967  }
968  }
969 
970  /* forward to data */
971  if( bmpinfo.InfoSize != 12 )
972  {
973  /* not old OS/2 format */
974  TRY( bmp_forward( f, bmpinfo.DataOffset ) );
975  }
976 
977  /* allocate greymap */
978  gm = gm_new( bmpinfo.w, bmpinfo.h );
979 
980  if( !gm )
981  {
982  goto std_error;
983  }
984 
985  realheight = 0;
986 
987  switch( bmpinfo.bits + 0x100 * bmpinfo.comp )
988  {
989  default:
990  goto format_error; break;
991 
992  case 0x001: /* monochrome palette */
993 
994  /* raster data */
995  for( y = 0; y < bmpinfo.h; y++ )
996  {
997  realheight = y + 1;
998  bmp_pad_reset();
999 
1000  for( i = 0; 8 * i < bmpinfo.w; i++ )
1001  {
1002  TRY_EOF( bmp_readint( f, 1, &b ) );
1003 
1004  for( j = 0; j < 8; j++ )
1005  {
1006  GM_PUT( gm, i * 8 + j, y, b & ( 0x80 >> j ) ? COLTABLE( 1 ) : COLTABLE( 0 ) );
1007  }
1008  }
1009 
1010  TRY( bmp_pad( f ) );
1011  }
1012 
1013  break;
1014 
1015  case 0x002: /* 2-bit to 8-bit palettes */
1016  case 0x003:
1017  case 0x004:
1018  case 0x005:
1019  case 0x006:
1020  case 0x007:
1021  case 0x008:
1022 
1023  for( y = 0; y < bmpinfo.h; y++ )
1024  {
1025  realheight = y + 1;
1026  bmp_pad_reset();
1027  bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */
1028  n = 0; /* number of bits currently in bitbuffer */
1029 
1030  for( x = 0; x < bmpinfo.w; x++ )
1031  {
1032  if( n < bmpinfo.bits )
1033  {
1034  TRY_EOF( bmp_readint( f, 1, &b ) );
1035  bitbuf |= b << ( INTBITS - 8 - n );
1036  n += 8;
1037  }
1038 
1039  b = bitbuf >> ( INTBITS - bmpinfo.bits );
1040  bitbuf <<= bmpinfo.bits;
1041  n -= bmpinfo.bits;
1042  GM_UPUT( gm, x, y, COLTABLE( b ) );
1043  }
1044 
1045  TRY( bmp_pad( f ) );
1046  }
1047 
1048  break;
1049 
1050  case 0x010: /* 16-bit encoding */
1051  /* can't do this format because it is not well-documented and I
1052  * don't have any samples */
1053  gm_read_error = "cannot handle bmp 16-bit coding";
1054  goto format_error;
1055  break;
1056 
1057  case 0x018: /* 24-bit encoding */
1058  case 0x020: /* 32-bit encoding */
1059 
1060  for( y = 0; y < bmpinfo.h; y++ )
1061  {
1062  realheight = y + 1;
1063  bmp_pad_reset();
1064 
1065  for( x = 0; x < bmpinfo.w; x++ )
1066  {
1067  TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
1068  c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff );
1069  GM_UPUT( gm, x, y, c / 3 );
1070  }
1071 
1072  TRY( bmp_pad( f ) );
1073  }
1074 
1075  break;
1076 
1077  case 0x320: /* 32-bit encoding with bitfields */
1078  redshift = lobit( bmpinfo.RedMask );
1079  greenshift = lobit( bmpinfo.GreenMask );
1080  blueshift = lobit( bmpinfo.BlueMask );
1081 
1082  for( y = 0; y < bmpinfo.h; y++ )
1083  {
1084  realheight = y + 1;
1085  bmp_pad_reset();
1086 
1087  for( x = 0; x < bmpinfo.w; x++ )
1088  {
1089  TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
1090  c = ( ( c & bmpinfo.RedMask ) >> redshift )
1091  + ( ( c & bmpinfo.GreenMask ) >> greenshift )
1092  + ( ( c & bmpinfo.BlueMask ) >> blueshift );
1093  GM_UPUT( gm, x, y, c / 3 );
1094  }
1095 
1096  TRY( bmp_pad( f ) );
1097  }
1098 
1099  break;
1100 
1101  case 0x204: /* 4-bit runlength compressed encoding (RLE4) */
1102  x = 0;
1103  y = 0;
1104 
1105  while( 1 )
1106  {
1107  TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */
1108  TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
1109 
1110  if( b > 0 )
1111  {
1112  /* repeat count */
1113  col[0] = COLTABLE( ( c >> 4 ) & 0xf );
1114  col[1] = COLTABLE( c & 0xf );
1115 
1116  for( i = 0; i < b && x < bmpinfo.w; i++ )
1117  {
1118  if( x >= bmpinfo.w )
1119  {
1120  x = 0;
1121  y++;
1122  }
1123 
1124  if( x >= bmpinfo.w || y >= bmpinfo.h )
1125  {
1126  break;
1127  }
1128 
1129  realheight = y + 1;
1130  GM_PUT( gm, x, y, col[i & 1] );
1131  x++;
1132  }
1133  }
1134  else if( c == 0 )
1135  {
1136  /* end of line */
1137  y++;
1138  x = 0;
1139  }
1140  else if( c == 1 )
1141  {
1142  /* end of greymap */
1143  break;
1144  }
1145  else if( c == 2 )
1146  {
1147  /* "delta": skip pixels in x and y directions */
1148  TRY_EOF( bmp_readint( f, 1, &b ) ); /* x offset */
1149  TRY_EOF( bmp_readint( f, 1, &c ) ); /* y offset */
1150  x += b;
1151  y += c;
1152  }
1153  else
1154  {
1155  /* verbatim segment */
1156  for( i = 0; i < c; i++ )
1157  {
1158  if( ( i & 1 ) == 0 )
1159  {
1160  TRY_EOF( bmp_readint( f, 1, &b ) );
1161  }
1162 
1163  if( x >= bmpinfo.w )
1164  {
1165  x = 0;
1166  y++;
1167  }
1168 
1169  if( x >= bmpinfo.w || y >= bmpinfo.h )
1170  {
1171  break;
1172  }
1173 
1174  realheight = y + 1;
1175  GM_PUT( gm, x, y, COLTABLE( ( b >> ( 4 - 4 * ( i & 1 ) ) ) & 0xf ) );
1176  x++;
1177  }
1178 
1179  if( ( c + 1 ) & 2 )
1180  {
1181  /* pad to 16-bit boundary */
1182  TRY_EOF( bmp_readint( f, 1, &b ) );
1183  }
1184  }
1185  }
1186 
1187  break;
1188 
1189  case 0x108: /* 8-bit runlength compressed encoding (RLE8) */
1190  x = 0;
1191  y = 0;
1192 
1193  while( 1 )
1194  {
1195  TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */
1196  TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
1197 
1198  if( b > 0 )
1199  {
1200  /* repeat count */
1201  for( i = 0; i < b; i++ )
1202  {
1203  if( x >= bmpinfo.w )
1204  {
1205  x = 0;
1206  y++;
1207  }
1208 
1209  if( x >= bmpinfo.w || y >= bmpinfo.h )
1210  {
1211  break;
1212  }
1213 
1214  realheight = y + 1;
1215  GM_PUT( gm, x, y, COLTABLE( c ) );
1216  x++;
1217  }
1218  }
1219  else if( c == 0 )
1220  {
1221  /* end of line */
1222  y++;
1223  x = 0;
1224  }
1225  else if( c == 1 )
1226  {
1227  /* end of greymap */
1228  break;
1229  }
1230  else if( c == 2 )
1231  {
1232  /* "delta": skip pixels in x and y directions */
1233  TRY_EOF( bmp_readint( f, 1, &b ) ); /* x offset */
1234  TRY_EOF( bmp_readint( f, 1, &c ) ); /* y offset */
1235  x += b;
1236  y += c;
1237  }
1238  else
1239  {
1240  /* verbatim segment */
1241  for( i = 0; i < c; i++ )
1242  {
1243  TRY_EOF( bmp_readint( f, 1, &b ) );
1244 
1245  if( x >= bmpinfo.w )
1246  {
1247  x = 0;
1248  y++;
1249  }
1250 
1251  if( x >= bmpinfo.w || y >= bmpinfo.h )
1252  {
1253  break;
1254  }
1255 
1256  realheight = y + 1;
1257  GM_PUT( gm, x, y, COLTABLE( b ) );
1258  x++;
1259  }
1260 
1261  if( c & 1 )
1262  {
1263  /* pad input to 16-bit boundary */
1264  TRY_EOF( bmp_readint( f, 1, &b ) );
1265  }
1266  }
1267  }
1268 
1269  break;
1270  } /* switch */
1271 
1272  /* skip any potential junk after the data section, but don't
1273  * complain in case EOF is encountered */
1274  bmp_forward( f, bmpinfo.FileSize );
1275 
1276  free( coltable );
1277 
1278  if( bmpinfo.topdown )
1279  {
1280  gm_flip( gm );
1281  }
1282 
1283  *gmp = gm;
1284  return 0;
1285 
1286 eof:
1287  TRY_STD( gm_resize( gm, realheight ) );
1288  free( coltable );
1289 
1290  if( bmpinfo.topdown )
1291  {
1292  gm_flip( gm );
1293  }
1294 
1295  *gmp = gm;
1296  return 1;
1297 
1298 format_error:
1299 try_error:
1300  free( coltable );
1301  gm_free( gm );
1302 
1303  if( !gm_read_error )
1304  {
1305  gm_read_error = "invalid bmp file";
1306  }
1307 
1308  return -2;
1309 
1310 std_error:
1311  free( coltable );
1312  gm_free( gm );
1313  return -1;
1314 }
unsigned int Planes
Definition: bitmap_io.cpp:500
unsigned int DataOffset
Definition: bitmap_io.cpp:496
static int bmp_pad(FILE *f)
Definition: greymap.cpp:780
#define TRY_STD(x)
Definition: greymap.cpp:36
unsigned int FileSize
Definition: bitmap_io.cpp:494
static void gm_flip(greymap_t *gm)
Definition: greymap.cpp:179
static int bmp_pos
Definition: greymap.cpp:742
#define COLTABLE(c)
Definition: greymap.cpp:825
void gm_free(greymap_t *gm)
Definition: greymap.cpp:122
unsigned int YpixelsPerM
Definition: bitmap_io.cpp:505
unsigned int reserved
Definition: bitmap_io.cpp:495
unsigned int ctbits
Definition: bitmap_io.cpp:512
unsigned int ColorsImportant
Definition: bitmap_io.cpp:507
unsigned int comp
Definition: bitmap_io.cpp:502
static unsigned int lobit(unsigned int x)
Definition: bitops.h:59
const char * gm_read_error
Definition: greymap.cpp:376
unsigned int InfoSize
Definition: bitmap_io.cpp:497
static int gm_resize(greymap_t *gm, int h)
Definition: greymap.cpp:199
static int bmp_forward(FILE *f, int pos)
Definition: greymap.cpp:803
#define TRY_EOF(x)
Definition: greymap.cpp:33
#define GM_UPUT(gm, x, y, b)
Definition: greymap.h:40
static void bmp_pad_reset(void)
Definition: greymap.cpp:772
unsigned int BlueMask
Definition: bitmap_io.cpp:510
unsigned int h
Definition: bitmap_io.cpp:499
unsigned int AlphaMask
Definition: bitmap_io.cpp:511
unsigned int GreenMask
Definition: bitmap_io.cpp:509
greymap_t * gm_new(int w, int h)
Definition: greymap.cpp:79
static int bmp_readint(FILE *f, int n, unsigned int *p)
Definition: greymap.cpp:746
unsigned int RedMask
Definition: bitmap_io.cpp:508
#define INTBITS
Definition: greymap.cpp:22
unsigned int ncolors
Definition: bitmap_io.cpp:506
unsigned int w
Definition: bitmap_io.cpp:498
#define TRY(x)
Definition: greymap.cpp:30
unsigned int ImageSize
Definition: bitmap_io.cpp:503
unsigned int XpixelsPerM
Definition: bitmap_io.cpp:504
#define GM_PUT(gm, x, y, b)
Definition: greymap.h:44
unsigned int bits
Definition: bitmap_io.cpp:501
static int gm_readbody_pnm ( FILE *  f,
greymap_t **  gmp,
int  magic 
)
static

Definition at line 415 of file greymap.cpp.

References bmp_info_s::AlphaMask, bmp_info_s::bits, bmp_info_s::BlueMask, bmp_info_s::ColorsImportant, bmp_info_s::comp, bmp_info_s::ctbits, bmp_info_s::DataOffset, bmp_info_s::FileSize, gm_flip(), gm_free(), gm_new(), GM_PUT, gm_read_error, gm_resize(), GM_UPUT, bmp_info_s::GreenMask, bmp_info_s::h, bmp_info_s::ImageSize, bmp_info_s::InfoSize, max, bmp_info_s::ncolors, bmp_info_s::Planes, readbit(), readnum(), bmp_info_s::RedMask, bmp_info_s::reserved, bmp_info_s::topdown, TRY_STD, bmp_info_s::w, bmp_info_s::XpixelsPerM, and bmp_info_s::YpixelsPerM.

Referenced by gm_read().

416 {
417  greymap_t* gm;
418  int x, y, i, j, b, b1, sum;
419  int bpr; /* bytes per row (as opposed to 4*gm->c) */
420  int w, h, max;
421  int realheight; /* in case of incomplete file, keeps track of how
422  * many scan lines actually contain data */
423 
424  gm = NULL;
425 
426  w = readnum( f );
427 
428  if( w < 0 )
429  {
430  goto format_error;
431  }
432 
433  h = readnum( f );
434 
435  if( h < 0 )
436  {
437  goto format_error;
438  }
439 
440  /* allocate greymap */
441  gm = gm_new( w, h );
442 
443  if( !gm )
444  {
445  goto std_error;
446  }
447 
448  realheight = 0;
449 
450  switch( magic )
451  {
452  default:
453  /* not reached */
454  goto format_error;
455 
456  case '1':
457  /* read P1 format: PBM ascii */
458 
459  for( y = 0; y < h; y++ )
460  {
461  realheight = y + 1;
462 
463  for( x = 0; x < w; x++ )
464  {
465  b = readbit( f );
466 
467  if( b < 0 )
468  {
469  goto eof;
470  }
471 
472  GM_UPUT( gm, x, y, b ? 0 : 255 );
473  }
474  }
475 
476  break;
477 
478  case '2':
479  /* read P2 format: PGM ascii */
480 
481  max = readnum( f );
482 
483  if( max < 1 )
484  {
485  goto format_error;
486  }
487 
488  for( y = 0; y < h; y++ )
489  {
490  realheight = y + 1;
491 
492  for( x = 0; x < w; x++ )
493  {
494  b = readnum( f );
495 
496  if( b < 0 )
497  {
498  goto eof;
499  }
500 
501  GM_UPUT( gm, x, y, b * 255 / max );
502  }
503  }
504 
505  break;
506 
507  case '3':
508  /* read P3 format: PPM ascii */
509 
510  max = readnum( f );
511 
512  if( max < 1 )
513  {
514  goto format_error;
515  }
516 
517  for( y = 0; y < h; y++ )
518  {
519  realheight = y + 1;
520 
521  for( x = 0; x < w; x++ )
522  {
523  sum = 0;
524 
525  for( i = 0; i < 3; i++ )
526  {
527  b = readnum( f );
528 
529  if( b < 0 )
530  {
531  goto eof;
532  }
533 
534  sum += b;
535  }
536 
537  GM_UPUT( gm, x, y, sum * ( 255 / 3 ) / max );
538  }
539  }
540 
541  break;
542 
543  case '4':
544  /* read P4 format: PBM raw */
545 
546  b = fgetc( f ); /* read single white-space character after height */
547 
548  if( b == EOF )
549  {
550  goto format_error;
551  }
552 
553  bpr = ( w + 7 ) / 8;
554 
555  for( y = 0; y < h; y++ )
556  {
557  realheight = y + 1;
558 
559  for( i = 0; i < bpr; i++ )
560  {
561  b = fgetc( f );
562 
563  if( b == EOF )
564  {
565  goto eof;
566  }
567 
568  for( j = 0; j < 8; j++ )
569  {
570  GM_PUT( gm, i * 8 + j, y, b & ( 0x80 >> j ) ? 0 : 255 );
571  }
572  }
573  }
574 
575  break;
576 
577  case '5':
578  /* read P5 format: PGM raw */
579 
580  max = readnum( f );
581 
582  if( max < 1 )
583  {
584  goto format_error;
585  }
586 
587  b = fgetc( f ); /* read single white-space character after max */
588 
589  if( b == EOF )
590  {
591  goto format_error;
592  }
593 
594  for( y = 0; y < h; y++ )
595  {
596  realheight = y + 1;
597 
598  for( x = 0; x < w; x++ )
599  {
600  b = fgetc( f );
601 
602  if( b == EOF )
603  goto eof;
604 
605  if( max >= 256 )
606  {
607  b <<= 8;
608  b1 = fgetc( f );
609 
610  if( b1 == EOF )
611  goto eof;
612 
613  b |= b1;
614  }
615 
616  GM_UPUT( gm, x, y, b * 255 / max );
617  }
618  }
619 
620  break;
621 
622  case '6':
623  /* read P6 format: PPM raw */
624 
625  max = readnum( f );
626 
627  if( max < 1 )
628  {
629  goto format_error;
630  }
631 
632  b = fgetc( f ); /* read single white-space character after max */
633 
634  if( b == EOF )
635  {
636  goto format_error;
637  }
638 
639  for( y = 0; y < h; y++ )
640  {
641  realheight = y + 1;
642 
643  for( x = 0; x < w; x++ )
644  {
645  sum = 0;
646 
647  for( i = 0; i < 3; i++ )
648  {
649  b = fgetc( f );
650 
651  if( b == EOF )
652  {
653  goto eof;
654  }
655 
656  if( max >= 256 )
657  {
658  b <<= 8;
659  b1 = fgetc( f );
660 
661  if( b1 == EOF )
662  goto eof;
663 
664  b |= b1;
665  }
666 
667  sum += b;
668  }
669 
670  GM_UPUT( gm, x, y, sum * ( 255 / 3 ) / max );
671  }
672  }
673 
674  break;
675  }
676 
677  gm_flip( gm );
678  *gmp = gm;
679  return 0;
680 
681 eof:
682  TRY_STD( gm_resize( gm, realheight ) );
683  gm_flip( gm );
684  *gmp = gm;
685  return 1;
686 
687 format_error:
688  gm_free( gm );
689 
690  if( magic == '1' || magic == '4' )
691  {
692  gm_read_error = "invalid pbm file";
693  }
694  else if( magic == '2' || magic == '5' )
695  {
696  gm_read_error = "invalid pgm file";
697  }
698  else
699  {
700  gm_read_error = "invalid ppm file";
701  }
702 
703  return -2;
704 
705 std_error:
706  gm_free( gm );
707  return -1;
708 }
#define TRY_STD(x)
Definition: greymap.cpp:36
static void gm_flip(greymap_t *gm)
Definition: greymap.cpp:179
void gm_free(greymap_t *gm)
Definition: greymap.cpp:122
static int readnum(FILE *f)
Definition: greymap.cpp:292
const char * gm_read_error
Definition: greymap.cpp:376
static int gm_resize(greymap_t *gm, int h)
Definition: greymap.cpp:199
#define GM_UPUT(gm, x, y, b)
Definition: greymap.h:40
#define max(a, b)
Definition: auxiliary.h:86
greymap_t * gm_new(int w, int h)
Definition: greymap.cpp:79
static int readbit(FILE *f)
Definition: greymap.cpp:342
#define GM_PUT(gm, x, y, b)
Definition: greymap.h:44
static int gm_resize ( greymap_t gm,
int  h 
)
inlinestatic

Definition at line 199 of file greymap.cpp.

References greymap_s::base, greymap_s::dy, getsize(), gm_flip(), greymap_s::h, and greymap_s::map.

Referenced by gm_readbody_bmp(), and gm_readbody_pnm().

200 {
201  int dy = gm->dy;
202  ptrdiff_t newsize;
203  gm_sample_t* newbase;
204 
205  if( dy < 0 )
206  {
207  gm_flip( gm );
208  }
209 
210  newsize = getsize( dy, h );
211 
212  if( newsize < 0 )
213  {
214  errno = ENOMEM;
215  goto error;
216  }
217 
218  if( newsize == 0 )
219  {
220  newsize = 1; /* make sure realloc() doesn't return NULL */
221  }
222 
223  newbase = (gm_sample_t*) realloc( gm->base, newsize );
224 
225  if( newbase == NULL )
226  {
227  goto error;
228  }
229 
230  gm->base = newbase;
231  gm->map = newbase;
232  gm->h = h;
233 
234  if( dy < 0 )
235  {
236  gm_flip( gm );
237  }
238 
239  return 0;
240 
241 error:
242 
243  if( dy < 0 )
244  {
245  gm_flip( gm );
246  }
247 
248  return 1;
249 }
int h
Definition: greymap.h:21
static ptrdiff_t getsize(int dy, int h)
Definition: greymap.cpp:46
static void gm_flip(greymap_t *gm)
Definition: greymap.cpp:179
gm_sample_t * base
Definition: greymap.h:24
gm_sample_t * map
Definition: greymap.h:25
int dy
Definition: greymap.h:22
signed short int gm_sample_t
Definition: greymap.h:13
static ptrdiff_t gm_size ( const greymap_t gm)
inlinestatic

Definition at line 71 of file greymap.cpp.

References greymap_s::dy, getsize(), and greymap_s::h.

Referenced by gm_clear().

72 {
73  return getsize( gm->dy, gm->h );
74 }
int h
Definition: greymap.h:21
static ptrdiff_t getsize(int dy, int h)
Definition: greymap.cpp:46
int dy
Definition: greymap.h:22
int gm_writepgm ( FILE *  f,
greymap_t gm,
const char *  comment,
int  raw,
int  mode,
double  gamma 
)

Definition at line 1325 of file greymap.cpp.

References GM_MODE_NEGATIVE, GM_MODE_NONZERO, GM_MODE_ODD, GM_MODE_POSITIVE, GM_UGET, greymap_s::h, mod, and greymap_s::w.

1326 {
1327  int x, y, v;
1328  int gammatable[256];
1329 
1330  /* prepare gamma correction lookup table */
1331  if( gamma != 1.0 )
1332  {
1333  gammatable[0] = 0;
1334 
1335  for( v = 1; v < 256; v++ )
1336  {
1337  gammatable[v] = (int) ( 255 * exp( log( v / 255.0 ) / gamma ) + 0.5 );
1338  }
1339  }
1340  else
1341  {
1342  for( v = 0; v < 256; v++ )
1343  {
1344  gammatable[v] = v;
1345  }
1346  }
1347 
1348  fprintf( f, raw ? "P5\n" : "P2\n" );
1349 
1350  if( comment && *comment )
1351  {
1352  fprintf( f, "# %s\n", comment );
1353  }
1354 
1355  fprintf( f, "%d %d 255\n", gm->w, gm->h );
1356 
1357  for( y = gm->h - 1; y >= 0; y-- )
1358  {
1359  for( x = 0; x < gm->w; x++ )
1360  {
1361  v = GM_UGET( gm, x, y );
1362 
1363  if( mode == GM_MODE_NONZERO )
1364  {
1365  if( v > 255 )
1366  {
1367  v = 510 - v;
1368  }
1369 
1370  if( v < 0 )
1371  {
1372  v = 0;
1373  }
1374  }
1375  else if( mode == GM_MODE_ODD )
1376  {
1377  v = mod( v, 510 );
1378 
1379  if( v > 255 )
1380  {
1381  v = 510 - v;
1382  }
1383  }
1384  else if( mode == GM_MODE_POSITIVE )
1385  {
1386  if( v < 0 )
1387  {
1388  v = 0;
1389  }
1390  else if( v > 255 )
1391  {
1392  v = 255;
1393  }
1394  }
1395  else if( mode == GM_MODE_NEGATIVE )
1396  {
1397  v = 510 - v;
1398 
1399  if( v < 0 )
1400  {
1401  v = 0;
1402  }
1403  else if( v > 255 )
1404  {
1405  v = 255;
1406  }
1407  }
1408 
1409  v = gammatable[v];
1410 
1411  if( raw )
1412  {
1413  fputc( v, f );
1414  }
1415  else
1416  {
1417  fprintf( f, x == gm->w - 1 ? "%d\n" : "%d ", v );
1418  }
1419  }
1420  }
1421 
1422  return 0;
1423 }
int h
Definition: greymap.h:21
#define GM_MODE_NEGATIVE
Definition: greymap.h:56
int w
Definition: greymap.h:20
#define GM_MODE_NONZERO
Definition: greymap.h:53
#define GM_MODE_ODD
Definition: greymap.h:54
#define GM_MODE_POSITIVE
Definition: greymap.h:55
#define mod(a, n)
Definition: greymap.cpp:24
#define GM_UGET(gm, x, y)
Definition: greymap.h:37
static int readbit ( FILE *  f)
static

Definition at line 342 of file greymap.cpp.

References fgetc_ws().

Referenced by gm_readbody_pnm().

343 {
344  int c;
345 
346  /* skip whitespace and comments */
347  while( 1 )
348  {
349  c = fgetc_ws( f );
350 
351  if( c == EOF )
352  {
353  return -1;
354  }
355 
356  if( c >= '0' && c <= '1' )
357  {
358  break;
359  }
360  }
361 
362  return c - '0';
363 }
static int fgetc_ws(FILE *f)
Definition: greymap.cpp:257
static int readnum ( FILE *  f)
static

Definition at line 292 of file greymap.cpp.

References fgetc_ws().

Referenced by gm_readbody_pnm().

293 {
294  int c;
295  int acc;
296 
297  /* skip whitespace and comments */
298  while( 1 )
299  {
300  c = fgetc_ws( f );
301 
302  if( c == EOF )
303  {
304  return -1;
305  }
306 
307  if( c >= '0' && c <= '9' )
308  {
309  break;
310  }
311  }
312 
313  /* first digit is already in c */
314  acc = c - '0';
315 
316  while( 1 )
317  {
318  c = fgetc( f );
319 
320  if( c == EOF )
321  {
322  break;
323  }
324 
325  if( c < '0' || c > '9' )
326  {
327  ungetc( c, f );
328  break;
329  }
330 
331  acc *= 10;
332  acc += c - '0';
333  }
334 
335  return acc;
336 }
static int fgetc_ws(FILE *f)
Definition: greymap.cpp:257

Variable Documentation

int bmp_count = 0
static

Definition at line 741 of file greymap.cpp.

Referenced by bmp_forward(), bmp_pad(), bmp_pad_reset(), and bmp_readint().

int bmp_pos = 0
static

Definition at line 742 of file greymap.cpp.

Referenced by bmp_forward(), bmp_pad(), bmp_readint(), and gm_readbody_bmp().

const char* gm_read_error = NULL

Definition at line 376 of file greymap.cpp.

Referenced by gm_readbody_bmp(), and gm_readbody_pnm().