diff --git a/potrace/auxiliary.h b/potrace/auxiliary.h index ba286492c6..0ff74fb980 100644 --- a/potrace/auxiliary.h +++ b/potrace/auxiliary.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -44,8 +44,8 @@ static inline dpoint_t interval( double lambda, dpoint_t a, dpoint_t b ) { dpoint_t res; - res.x = a.x + lambda * (b.x - a.x); - res.y = a.y + lambda * (b.y - a.y); + res.x = a.x + lambda * ( b.x - a.x ); + res.y = a.y + lambda * ( b.y - a.y ); return res; } @@ -63,13 +63,13 @@ static inline dpoint_t interval( double lambda, dpoint_t a, dpoint_t b ) static inline int mod( int a, int n ) { - return a>=n ? a % n : a>=0 ? a : n - 1 - (-1 - a) % n; + return a >= n ? a % n : a >= 0 ? a : n - 1 - ( -1 - a ) % n; } static inline int floordiv( int a, int n ) { - return a>=0 ? a / n : -1 - (-1 - a) / n; + return a >= 0 ? a / n : -1 - ( -1 - a ) / n; } @@ -80,11 +80,11 @@ static inline int floordiv( int a, int n ) #undef max #undef sq #undef cu -#define sign( x ) ( (x)>0 ? 1 : (x)<0 ? -1 : 0 ) -#define abs( a ) ( (a)>0 ? (a) : -(a) ) -#define min( a, b ) ( (a)<(b) ? (a) : (b) ) -#define max( a, b ) ( (a)>(b) ? (a) : (b) ) -#define sq( a ) ( (a) * (a) ) -#define cu( a ) ( (a) * (a) * (a) ) +#define sign( x ) ( ( x ) > 0 ? 1 : ( x ) < 0 ? -1 : 0 ) +#define abs( a ) ( ( a ) > 0 ? ( a ) : -( a ) ) +#define min( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) ) +#define max( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) ) +#define sq( a ) ( ( a ) * ( a ) ) +#define cu( a ) ( ( a ) * ( a ) * ( a ) ) #endif /* AUXILIARY_H */ diff --git a/potrace/bitmap.h b/potrace/bitmap.h index 5700616145..bc5f945c5b 100644 --- a/potrace/bitmap.h +++ b/potrace/bitmap.h @@ -1,14 +1,14 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ #ifndef BITMAP_H #define BITMAP_H -#include -#include #include #include +#include +#include /* The bitmap type is defined in potracelib.h */ #include "potracelib.h" @@ -21,58 +21,117 @@ /* ---------------------------------------------------------------------- */ /* some measurements */ -#define BM_WORDSIZE ( (int) sizeof(potrace_word) ) -#define BM_WORDBITS (8 * BM_WORDSIZE) -#define BM_HIBIT ( ( (potrace_word) 1 ) << (BM_WORDBITS - 1) ) -#define BM_ALLBITS (~(potrace_word) 0) +#define BM_WORDSIZE ( (int) sizeof( potrace_word ) ) +#define BM_WORDBITS ( 8 * BM_WORDSIZE ) +#define BM_HIBIT ( ( (potrace_word) 1 ) << ( BM_WORDBITS - 1 ) ) +#define BM_ALLBITS ( ~(potrace_word) 0 ) /* macros for accessing pixel at index (x,y). U* macros omit the * bounds check. */ -#define bm_scanline( bm, y ) ( (bm)->map + (ptrdiff_t) (y) * (ptrdiff_t) (bm)->dy ) -#define bm_index( bm, x, y ) (&bm_scanline( bm, y )[(x) / BM_WORDBITS]) -#define bm_mask( x ) ( BM_HIBIT >> ( (x) & (BM_WORDBITS - 1) ) ) -#define bm_range( x, a ) ( (int) (x) >= 0 && (int) (x) < (a) ) -#define bm_safe( bm, x, y ) ( bm_range( x, (bm)->w ) && bm_range( y, (bm)->h ) ) +#define bm_scanline( bm, y ) ( ( bm )->map + (ptrdiff_t) ( y ) * (ptrdiff_t) ( bm )->dy ) +#define bm_index( bm, x, y ) ( &bm_scanline( bm, y )[( x ) / BM_WORDBITS] ) +#define bm_mask( x ) ( BM_HIBIT >> ( ( x ) & ( BM_WORDBITS - 1 ) ) ) +#define bm_range( x, a ) ( (int) ( x ) >= 0 && (int) ( x ) < ( a ) ) +#define bm_safe( bm, x, y ) ( bm_range( x, ( bm )->w ) && bm_range( y, ( bm )->h ) ) #define BM_UGET( bm, x, y ) ( ( *bm_index( bm, x, y ) & bm_mask( x ) ) != 0 ) #define BM_USET( bm, x, y ) ( *bm_index( bm, x, y ) |= bm_mask( x ) ) #define BM_UCLR( bm, x, y ) ( *bm_index( bm, x, y ) &= ~bm_mask( x ) ) #define BM_UINV( bm, x, y ) ( *bm_index( bm, x, y ) ^= bm_mask( x ) ) -#define BM_UPUT( bm, x, y, b ) ( (b) ? BM_USET( bm, x, y ) : BM_UCLR( bm, x, y ) ) -#define BM_GET( bm, x, y ) (bm_safe( bm, x, y ) ? BM_UGET( bm, x, y ) : 0) -#define BM_SET( bm, x, y ) (bm_safe( bm, x, y ) ? BM_USET( bm, x, y ) : 0) -#define BM_CLR( bm, x, y ) (bm_safe( bm, x, y ) ? BM_UCLR( bm, x, y ) : 0) -#define BM_INV( bm, x, y ) (bm_safe( bm, x, y ) ? BM_UINV( bm, x, y ) : 0) -#define BM_PUT( bm, x, y, b ) (bm_safe( bm, x, y ) ? BM_UPUT( bm, x, y, b ) : 0) +#define BM_UPUT( bm, x, y, b ) ( ( b ) ? BM_USET( bm, x, y ) : BM_UCLR( bm, x, y ) ) +#define BM_GET( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_UGET( bm, x, y ) : 0 ) +#define BM_SET( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_USET( bm, x, y ) : 0 ) +#define BM_CLR( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_UCLR( bm, x, y ) : 0 ) +#define BM_INV( bm, x, y ) ( bm_safe( bm, x, y ) ? BM_UINV( bm, x, y ) : 0 ) +#define BM_PUT( bm, x, y, b ) ( bm_safe( bm, x, y ) ? BM_UPUT( bm, x, y, b ) : 0 ) + +/* calculate the size, in bytes, required for the data area of a + * bitmap of the given dy and h. Assume h >= 0. Return -1 if the size + * does not fit into the ptrdiff_t type. */ +static inline ptrdiff_t getsize( int dy, int h ) +{ + ptrdiff_t size; + + if( dy < 0 ) + { + dy = -dy; + } + + size = (ptrdiff_t) dy * (ptrdiff_t) h * (ptrdiff_t) BM_WORDSIZE; + + /* check for overflow error */ + if( size < 0 || ( h != 0 && dy != 0 && size / h / dy != BM_WORDSIZE ) ) + { + return -1; + } + + return size; +} + + +/* return the size, in bytes, of the data area of the bitmap. Return + * -1 if the size does not fit into the ptrdiff_t type; however, this + * cannot happen if the bitmap is well-formed, i.e., if created with + * bm_new or bm_dup. */ +static inline ptrdiff_t bm_size( const potrace_bitmap_t* bm ) +{ + return getsize( bm->dy, bm->h ); +} + + +/* calculate the base address of the bitmap data. Assume that the + * bitmap is well-formed, i.e., its size fits into the ptrdiff_t type. + * This is the case if created with bm_new or bm_dup. The base address + * may differ from bm->map if dy is negative */ +static inline potrace_word* bm_base( const potrace_bitmap_t* bm ) +{ + int dy = bm->dy; + + if( dy >= 0 || bm->h == 0 ) + { + return bm->map; + } + else + { + return bm_scanline( bm, bm->h - 1 ); + } +} + /* free the given bitmap. Leaves errno untouched. */ static inline void bm_free( potrace_bitmap_t* bm ) { - if( bm ) + if( bm && bm->map ) { - free( bm->map ); + free( bm_base( bm ) ); } free( bm ); } -/* return new un-initialized bitmap. NULL with errno on error. +/* return new bitmap initialized to 0. NULL with errno on error. * Assumes w, h >= 0. */ static inline potrace_bitmap_t* bm_new( int w, int h ) { potrace_bitmap_t* bm; - int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1; - ptrdiff_t size = (ptrdiff_t) dy * (ptrdiff_t) h * (ptrdiff_t) BM_WORDSIZE; + int dy = w == 0 ? 0 : ( w - 1 ) / BM_WORDBITS + 1; + ptrdiff_t size; - /* check for overflow error */ - if( size < 0 || (h != 0 && dy != 0 && size / h / dy != BM_WORDSIZE) ) + size = getsize( dy, h ); + + if( size < 0 ) { errno = ENOMEM; return NULL; } - bm = (potrace_bitmap_t*) malloc( sizeof(potrace_bitmap_t) ); + if( size == 0 ) + { + size = 1; /* make sure calloc() doesn't return NULL */ + } + + bm = (potrace_bitmap_t*) malloc( sizeof( potrace_bitmap_t ) ); if( !bm ) { @@ -82,7 +141,7 @@ static inline potrace_bitmap_t* bm_new( int w, int h ) bm->w = w; bm->h = h; bm->dy = dy; - bm->map = (potrace_word*) malloc( size ); + bm->map = (potrace_word*) calloc( 1, size ); if( !bm->map ) { @@ -94,29 +153,36 @@ static inline potrace_bitmap_t* bm_new( int w, int h ) } -/* clear the given bitmap. Set all bits to c. */ +/* clear the given bitmap. Set all bits to c. Assumes a well-formed + * bitmap. */ static inline void bm_clear( potrace_bitmap_t* bm, int c ) { /* Note: if the bitmap was created with bm_new, then it is * guaranteed that size will fit into the ptrdiff_t type. */ - ptrdiff_t size = (ptrdiff_t) bm->dy * (ptrdiff_t) bm->h * (ptrdiff_t) BM_WORDSIZE; + ptrdiff_t size = bm_size( bm ); - memset( bm->map, c ? -1 : 0, size ); + memset( bm_base( bm ), c ? -1 : 0, size ); } -/* duplicate the given bitmap. Return NULL on error with errno set. */ +/* duplicate the given bitmap. Return NULL on error with errno + * set. Assumes a well-formed bitmap. */ static inline potrace_bitmap_t* bm_dup( const potrace_bitmap_t* bm ) { potrace_bitmap_t* bm1 = bm_new( bm->w, bm->h ); - ptrdiff_t size = (ptrdiff_t) bm->dy * (ptrdiff_t) bm->h * (ptrdiff_t) BM_WORDSIZE; + int y; if( !bm1 ) { return NULL; } - memcpy( bm1->map, bm->map, size ); + for( y = 0; y < bm->h; y++ ) + { + memcpy( bm_scanline( bm1, y ), bm_scanline( bm, y ), + (size_t) bm1->dy * (size_t) BM_WORDSIZE ); + } + return bm1; } @@ -124,14 +190,100 @@ static inline potrace_bitmap_t* bm_dup( const potrace_bitmap_t* bm ) /* invert the given bitmap. */ static inline void bm_invert( potrace_bitmap_t* bm ) { - ptrdiff_t i; - ptrdiff_t size = (ptrdiff_t) bm->dy * (ptrdiff_t) bm->h; + int dy = bm->dy; + int y; + int i; + potrace_word* p; - for( i = 0; i < size; i++ ) + if( dy < 0 ) { - bm->map[i] ^= BM_ALLBITS; + dy = -dy; + } + + for( y = 0; y < bm->h; y++ ) + { + p = bm_scanline( bm, y ); + + for( i = 0; i < dy; i++ ) + { + p[i] ^= BM_ALLBITS; + } } } +/* turn the given bitmap upside down. This does not move the bitmap + * data or change the bm_base() address. */ +static inline void bm_flip( potrace_bitmap_t* bm ) +{ + int dy = bm->dy; + + if( bm->h == 0 || bm->h == 1 ) + { + return; + } + + bm->map = bm_scanline( bm, bm->h - 1 ); + bm->dy = -dy; +} + + +/* resize the bitmap to the given new height. The bitmap data remains + * bottom-aligned (truncated at the top) when dy >= 0 and top-aligned + * (truncated at the bottom) when dy < 0. Return 0 on success, or 1 on + * error with errno set. If the new height is <= the old one, no error + * should occur. If the new height is larger, the additional bitmap + * data is *not* initialized. */ +static inline int bm_resize( potrace_bitmap_t* bm, int h ) +{ + int dy = bm->dy; + ptrdiff_t newsize; + potrace_word* newmap; + + if( dy < 0 ) + { + bm_flip( bm ); + } + + newsize = getsize( dy, h ); + + if( newsize < 0 ) + { + errno = ENOMEM; + goto error; + } + + if( newsize == 0 ) + { + newsize = 1; /* make sure realloc() doesn't return NULL */ + } + + newmap = (potrace_word*) realloc( bm->map, newsize ); + + if( newmap == NULL ) + { + goto error; + } + + bm->map = newmap; + bm->h = h; + + if( dy < 0 ) + { + bm_flip( bm ); + } + + return 0; + +error: + + if( dy < 0 ) + { + bm_flip( bm ); + } + + return 1; +} + + #endif /* BITMAP_H */ diff --git a/potrace/bitmap_io.cpp b/potrace/bitmap_io.cpp index 0459dbe461..d9a0e61ea0 100644 --- a/potrace/bitmap_io.cpp +++ b/potrace/bitmap_io.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -12,13 +12,24 @@ #include #include "bitmap.h" +#include "bitmap_io.h" #include "bitops.h" -#define INTBITS ( 8 * sizeof(int) ) +#define INTBITS ( 8 * sizeof( int ) ) static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ); static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, int magic ); +#define TRY( x ) \ + if( x ) \ + goto try_error +#define TRY_EOF( x ) \ + if( x ) \ + goto eof +#define TRY_STD( x ) \ + if( x ) \ + goto std_error + /* ---------------------------------------------------------------------- */ /* routines for reading pnm streams */ @@ -32,13 +43,13 @@ static int fgetc_ws( FILE* f ) { c = fgetc( f ); - if( c=='#' ) + if( c == '#' ) { while( 1 ) { c = fgetc( f ); - if( c=='\n' || c==EOF ) + if( c == '\n' || c == EOF ) { break; } @@ -46,7 +57,7 @@ static int fgetc_ws( FILE* f ) } /* space, tab, line feed, carriage return, form-feed */ - if( c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12 ) + if( c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != 12 ) { return c; } @@ -69,12 +80,12 @@ static int readnum( FILE* f ) { c = fgetc_ws( f ); - if( c==EOF ) + if( c == EOF ) { return -1; } - if( c>='0' && c<='9' ) + if( c >= '0' && c <= '9' ) { break; } @@ -87,12 +98,12 @@ static int readnum( FILE* f ) { c = fgetc( f ); - if( c==EOF ) + if( c == EOF ) { break; } - if( c<'0' || c>'9' ) + if( c < '0' || c > '9' ) { ungetc( c, f ); break; @@ -118,12 +129,12 @@ static int readbit( FILE* f ) { c = fgetc_ws( f ); - if( c==EOF ) + if( c == EOF ) { return -1; } - if( c>='0' && c<='1' ) + if( c >= '0' && c <= '1' ) { break; } @@ -185,21 +196,23 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i { potrace_bitmap_t* bm; int x, y, i, b, b1, sum; - int bpr; /* bytes per row (as opposed to 4*bm->c) */ + int bpr; /* bytes per row (as opposed to 4*bm->c) */ int w, h, max; + int realheight; /* in case of incomplete file, keeps track of how + * many scan lines actually contain data */ bm = NULL; w = readnum( f ); - if( w<0 ) + if( w < 0 ) { goto format_error; } h = readnum( f ); - if( h<0 ) + if( h < 0 ) { goto format_error; } @@ -209,11 +222,10 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i if( !bm ) { - return -1; + goto std_error; } - /* zero it out */ - bm_clear( bm, 0 ); + realheight = 0; switch( magic ) { @@ -224,13 +236,15 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i case '1': /* read P1 format: PBM ascii */ - for( y = h - 1; y>=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=0; y-- ) + for( y = 0; y < h; y++ ) { - for( i = 0; i=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=256 ) + if( max >= 256 ) { b <<= 8; b1 = fgetc( f ); - if( b1==EOF ) + if( b1 == EOF ) goto eof; b |= b1; @@ -381,39 +402,41 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i max = readnum( f ); - if( max<1 ) + if( max < 1 ) { goto format_error; } b = fgetc( f ); /* read single white-space character after max */ - if( b==EOF ) + if( b == EOF ) { goto format_error; } - for( y = h - 1; y>=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=256 ) + if( max >= 256 ) { b <<= 8; b1 = fgetc( f ); - if( b1==EOF ) + if( b1 == EOF ) goto eof; b |= b1; @@ -429,10 +452,13 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i break; } + bm_flip( bm ); *bmp = bm; return 0; eof: + TRY_STD( bm_resize( bm, realheight ) ); + bm_flip( bm ); *bmp = bm; return 1; @@ -453,6 +479,10 @@ format_error: } return -2; + +std_error: + bm_free( bm ); + return -1; } @@ -465,22 +495,22 @@ struct bmp_info_s unsigned int reserved; unsigned int DataOffset; unsigned int InfoSize; - unsigned int w; /* width */ - unsigned int h; /* height */ + unsigned int w; /* width */ + unsigned int h; /* height */ unsigned int Planes; - unsigned int bits; /* bits per sample */ - unsigned int comp; /* compression mode */ + unsigned int bits; /* bits per sample */ + unsigned int comp; /* compression mode */ unsigned int ImageSize; unsigned int XpixelsPerM; unsigned int YpixelsPerM; - unsigned int ncolors; /* number of colors in palette */ + unsigned int ncolors; /* number of colors in palette */ unsigned int ColorsImportant; unsigned int RedMask; unsigned int GreenMask; unsigned int BlueMask; unsigned int AlphaMask; - unsigned int ctbits; /* sample size for color table */ - int topdown; /* top-down mode? */ + unsigned int ctbits; /* sample size for color table */ + int topdown; /* top-down mode? */ }; typedef struct bmp_info_s bmp_info_t; @@ -497,16 +527,16 @@ static int bmp_readint( FILE* f, int n, unsigned int* p ) unsigned int sum = 0; int b; - for( i = 0; i= 108 ) /* V4 and V5 bitmaps */ + if( bmpinfo.InfoSize >= 108 ) { + /* V4 and V5 bitmaps */ TRY( bmp_readint( f, 4, &bmpinfo.RedMask ) ); TRY( bmp_readint( f, 4, &bmpinfo.GreenMask ) ); TRY( bmp_readint( f, 4, &bmpinfo.BlueMask ) ); @@ -647,7 +672,7 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) if( bmpinfo.h > 0x7fffffff ) { - bmpinfo.h = (-bmpinfo.h) & 0xffffffff; + bmpinfo.h = ( -bmpinfo.h ) & 0xffffffff; bmpinfo.topdown = 1; } else @@ -697,7 +722,7 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) goto format_error; /* can't handle planes */ } - if( bmpinfo.ncolors == 0 ) + if( bmpinfo.ncolors == 0 && bmpinfo.bits <= 8 ) { bmpinfo.ncolors = 1 << bmpinfo.bits; } @@ -705,7 +730,7 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) /* color table, present only if bmpinfo.bits <= 8. */ if( bmpinfo.bits <= 8 ) { - coltable = (int*) calloc( bmpinfo.ncolors, sizeof(int) ); + coltable = (int*) calloc( bmpinfo.ncolors, sizeof( int ) ); if( !coltable ) { @@ -714,13 +739,13 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) /* NOTE: since we are reading a bitmap, we can immediately convert * the color table entries to bits. */ - for( i = 0; i> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff); - coltable[i] = (c > 3 * threshold * 255 ? 0 : 1); + c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff ); + coltable[i] = ( c > 3 * threshold * 255 ? 0 : 1 ); - if( i<2 ) + if( i < 2 ) { col1[i] = c; } @@ -728,8 +753,9 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) } /* forward to data */ - if( bmpinfo.InfoSize != 12 ) /* not old OS/2 format */ + if( bmpinfo.InfoSize != 12 ) { + /* not old OS/2 format */ TRY( bmp_forward( f, bmpinfo.DataOffset ) ); } @@ -741,19 +767,18 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) goto std_error; } - /* zero it out */ - bm_clear( bm, 0 ); + realheight = 0; switch( bmpinfo.bits + 0x100 * bmpinfo.comp ) { default: - goto format_error; - break; + goto format_error; break; - case 0x001: /* monochrome palette */ + case 0x001: /* monochrome palette */ - if( col1[0] < col1[1] ) /* make the darker color black */ + if( col1[0] < col1[1] ) { + /* make the darker color black */ mask = 0xff; } else @@ -762,17 +787,17 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) } /* raster data */ - for( y = 0; y> (INTBITS - bmpinfo.bits); + b = bitbuf >> ( INTBITS - bmpinfo.bits ); bitbuf <<= bmpinfo.bits; n -= bmpinfo.bits; - BM_UPUT( bm, x, ycorr( y ), COLTABLE( b ) ); + BM_UPUT( bm, x, y, COLTABLE( b ) ); } TRY( bmp_pad( f ) ); @@ -824,15 +850,16 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) case 0x018: /* 24-bit encoding */ case 0x020: /* 32-bit encoding */ - for( y = 0; y> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff); - BM_UPUT( bm, x, ycorr( y ), c > 3 * threshold * 255 ? 0 : 1 ); + c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff ); + BM_UPUT( bm, x, y, c > 3 * threshold * 255 ? 0 : 1 ); } TRY( bmp_pad( f ) ); @@ -841,21 +868,28 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) break; case 0x320: /* 32-bit encoding with bitfields */ + + if( bmpinfo.RedMask == 0 || bmpinfo.GreenMask == 0 || bmpinfo.BlueMask == 0 ) + { + goto format_error; + } + redshift = lobit( bmpinfo.RedMask ); greenshift = lobit( bmpinfo.GreenMask ); blueshift = lobit( bmpinfo.BlueMask ); - for( y = 0; y> redshift ) + - ( (c & bmpinfo.GreenMask) >> greenshift ) + - ( (c & bmpinfo.BlueMask) >> blueshift ); - BM_UPUT( bm, x, ycorr( y ), c > 3 * threshold * 255 ? 0 : 1 ); + c = ( ( c & bmpinfo.RedMask ) >> redshift ) + + ( ( c & bmpinfo.GreenMask ) >> greenshift ) + + ( ( c & bmpinfo.BlueMask ) >> blueshift ); + BM_UPUT( bm, x, y, c > 3 * threshold * 255 ? 0 : 1 ); } TRY( bmp_pad( f ) ); @@ -872,26 +906,27 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */ TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */ - if( b>0 ) + if( b > 0 ) { /* repeat count */ - col[0] = COLTABLE( (c >> 4) & 0xf ); + col[0] = COLTABLE( ( c >> 4 ) & 0xf ); col[1] = COLTABLE( c & 0xf ); - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - BM_UPUT( bm, x, ycorr( y ), col[i & 1] ); + realheight = y + 1; + BM_PUT( bm, x, y, col[i & 1] ); x++; } } @@ -917,29 +952,30 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) else { /* verbatim segment */ - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - BM_PUT( bm, x, ycorr( y ), COLTABLE( ( b >> ( 4 - 4 * (i & 1) ) ) & 0xf ) ); + realheight = y + 1; + BM_PUT( bm, x, y, COLTABLE( ( b >> ( 4 - 4 * ( i & 1 ) ) ) & 0xf ) ); x++; } - if( (c + 1) & 2 ) + if( ( c + 1 ) & 2 ) { /* pad to 16-bit boundary */ TRY_EOF( bmp_readint( f, 1, &b ) ); @@ -958,23 +994,24 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */ TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */ - if( b>0 ) + if( b > 0 ) { /* repeat count */ - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - BM_UPUT( bm, x, ycorr( y ), COLTABLE( c ) ); + realheight = y + 1; + BM_PUT( bm, x, y, COLTABLE( c ) ); x++; } } @@ -1000,22 +1037,23 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) else { /* verbatim segment */ - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - BM_PUT( bm, x, ycorr( y ), COLTABLE( b ) ); + realheight = y + 1; + BM_PUT( bm, x, y, COLTABLE( b ) ); x++; } @@ -1035,11 +1073,24 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp ) bmp_forward( f, bmpinfo.FileSize ); free( coltable ); + + if( bmpinfo.topdown ) + { + bm_flip( bm ); + } + *bmp = bm; return 0; eof: + TRY_STD( bm_resize( bm, realheight ) ); free( coltable ); + + if( bmpinfo.topdown ) + { + bm_flip( bm ); + } + *bmp = bm; return 1; @@ -1072,17 +1123,16 @@ void bm_writepbm( FILE* f, potrace_bitmap_t* bm ) w = bm->w; h = bm->h; - bpr = (w + 7) / 8; + bpr = ( w + 7 ) / 8; fprintf( f, "P4\n%d %d\n", w, h ); - for( y = h - 1; y>=0; y-- ) + for( y = h - 1; y >= 0; y-- ) { - for( i = 0; i> ( 8 * ( BM_WORDSIZE - 1 - (i % BM_WORDSIZE) ) ) ) & 0xff; + c = ( *bm_index( bm, i * 8, y ) >> ( 8 * ( BM_WORDSIZE - 1 - ( i % BM_WORDSIZE ) ) ) ) + & 0xff; fputc( c, f ); } } @@ -1101,17 +1151,17 @@ int bm_print( FILE* f, potrace_bitmap_t* bm ) int sw, sh; sw = bm->w < 79 ? bm->w : 79; - sh = bm->w < 79 ? bm->h : bm->h * sw * 44 / (79 * bm->w); + sh = bm->w < 79 ? bm->h : bm->h * sw * 44 / ( 79 * bm->w ); - for( yy = sh - 1; yy>=0; yy-- ) + for( yy = sh - 1; yy >= 0; yy-- ) { - for( xx = 0; xxw / sw; x<(xx + 1) * bm->w / sw; x++ ) + for( x = xx * bm->w / sw; x < ( xx + 1 ) * bm->w / sw; x++ ) { - for( y = yy * bm->h / sh; y<(yy + 1) * bm->h / sh; y++ ) + for( y = yy * bm->h / sh; y < ( yy + 1 ) * bm->h / sh; y++ ) { if( BM_GET( bm, x, y ) ) { diff --git a/potrace/bitmap_io.h b/potrace/bitmap_io.h index 5cfed8f5cb..cb2b3d7f2f 100644 --- a/potrace/bitmap_io.h +++ b/potrace/bitmap_io.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -7,8 +7,8 @@ #ifndef BITMAP_IO_H #define BITMAP_IO_H -#include #include "bitmap.h" +#include /* Note that bitmaps are stored bottom to top, i.e., the first * scanline is the bottom-most one */ diff --git a/potrace/bitops.h b/potrace/bitops.h index 59da00dd93..4d5a722435 100644 --- a/potrace/bitops.h +++ b/potrace/bitops.h @@ -1,8 +1,7 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ - /* bits.h: this file defines some macros for bit manipulations. We * provide a generic implementation, as well as machine- and * compiler-specific fast implementations */ @@ -22,19 +21,19 @@ /* ---------------------------------------------------------------------- */ /* machine specific macros */ -#if defined(HAVE_I386) +#if defined( HAVE_I386 ) static inline unsigned int lobit( unsigned int x ) { unsigned int res; - asm ("bsf %1,%0\n\t" - "jnz 0f\n\t" - "movl $32,%0\n" - "0:" - : "=r" (res) - : "r" (x) - : "cc"); + asm ( "bsf %1,%0\n\t" + "jnz 0f\n\t" + "movl $32,%0\n" + "0:" + : "=r" ( res ) + : "r" ( x ) + : "cc" ); return res; } @@ -43,13 +42,13 @@ static inline unsigned int hibit( unsigned int x ) { unsigned int res; - asm ("bsr %1,%0\n\t" - "jnz 0f\n\t" - "movl $-1,%0\n" - "0:" - : "=r" (res) - : "r" (x) - : "cc"); + asm ( "bsr %1,%0\n\t" + "jnz 0f\n\t" + "movl $-1,%0\n" + "0:" + : "=r" ( res ) + : "r" ( x ) + : "cc" ); return res + 1; } diff --git a/potrace/curve.cpp b/potrace/curve.cpp index ba410fd23e..f6ff0bbc05 100644 --- a/potrace/curve.cpp +++ b/potrace/curve.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -12,12 +12,12 @@ #include #include -#include "potracelib.h" -#include "lists.h" #include "curve.h" +#include "lists.h" +#include "potracelib.h" -#define SAFE_CALLOC( var, n, typ ) \ - if( ( var = (typ*) calloc( n, sizeof(typ) ) ) == NULL ) \ +#define SAFE_CALLOC( var, n, typ ) \ + if( ( var = (typ*) calloc( n, sizeof( typ ) ) ) == NULL ) \ goto calloc_error /* ---------------------------------------------------------------------- */ @@ -29,9 +29,9 @@ path_t* path_new( void ) privpath_t* priv = NULL; SAFE_CALLOC( p, 1, path_t ); - memset( p, 0, sizeof(path_t) ); + memset( p, 0, sizeof( path_t ) ); SAFE_CALLOC( priv, 1, privpath_t ); - memset( priv, 0, sizeof(privpath_t) ); + memset( priv, 0, sizeof( privpath_t ) ); p->priv = priv; return p; @@ -97,7 +97,7 @@ typedef dpoint_t dpoint3_t[3]; * Return 0 on success, 1 on error with errno set. */ int privcurve_init( privcurve_t* curve, int n ) { - memset( curve, 0, sizeof(privcurve_t) ); + memset( curve, 0, sizeof( privcurve_t ) ); curve->n = n; SAFE_CALLOC( curve->tag, n, int ); SAFE_CALLOC( curve->c, n, dpoint3_t ); diff --git a/potrace/curve.h b/potrace/curve.h index fa4f82fcd6..55999ab8c3 100644 --- a/potrace/curve.h +++ b/potrace/curve.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ diff --git a/potrace/decompose.cpp b/potrace/decompose.cpp index d0ec5af928..cb34f29eba 100644 --- a/potrace/decompose.cpp +++ b/potrace/decompose.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -6,16 +6,21 @@ #include #endif +#include + +#include #include #include #include -#include +#ifdef HAVE_INTTYPES_H +#include +#endif -#include "potracelib.h" -#include "curve.h" -#include "lists.h" #include "bitmap.h" +#include "curve.h" #include "decompose.h" +#include "lists.h" +#include "potracelib.h" #include "progress.h" /* ---------------------------------------------------------------------- */ @@ -28,23 +33,22 @@ static inline int detrand( int x, int y ) { /* non-linear sequence: constant term of inverse in GF(8), * mod x^8+x^4+x^3+x+1 */ - 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, - 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, - 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, - 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, - 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, - 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 0, + 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, + 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, + 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, + 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, }; /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible * 5-bit sequence */ - z = ( (0x04b3e375 * x) ^ y ) * 0x05a8ef93; - z = t[z & 0xff] ^ t[(z >> 8) & 0xff] ^ t[(z >> 16) & 0xff] ^ t[(z >> 24) & 0xff]; + z = ( ( 0x04b3e375 * x ) ^ y ) * 0x05a8ef93; + z = t[z & 0xff] ^ t[( z >> 8 ) & 0xff] ^ t[( z >> 16 ) & 0xff] ^ t[( z >> 24 ) & 0xff]; return z; } @@ -60,9 +64,9 @@ static void bm_clearexcess( potrace_bitmap_t* bm ) if( bm->w % BM_WORDBITS != 0 ) { - mask = BM_ALLBITS << ( BM_WORDBITS - (bm->w % BM_WORDBITS) ); + mask = BM_ALLBITS << ( BM_WORDBITS - ( bm->w % BM_WORDBITS ) ); - for( y = 0; yh; y++ ) + for( y = 0; y < bm->h; y++ ) { *bm_index( bm, bm->w, y ) &= mask; } @@ -80,13 +84,13 @@ typedef struct bbox_s bbox_t; * than clearing the whole bitmap) */ static void clear_bm_with_bbox( potrace_bitmap_t* bm, bbox_t* bbox ) { - int imin = (bbox->x0 / BM_WORDBITS); - int imax = ( (bbox->x1 + BM_WORDBITS - 1) / BM_WORDBITS ); + int imin = ( bbox->x0 / BM_WORDBITS ); + int imax = ( ( bbox->x1 + BM_WORDBITS - 1 ) / BM_WORDBITS ); int i, y; - for( y = bbox->y0; yy1; y++ ) + for( y = bbox->y0; y < bbox->y1; y++ ) { - for( i = imin; i0 ) + if( ct > 0 ) { return 1; } - else if( ct<0 ) + else if( ct < 0 ) { return 0; } @@ -137,10 +142,10 @@ static int majority( potrace_bitmap_t* bm, int x, int y ) static void xor_to_ref( potrace_bitmap_t* bm, int x, int y, int xa ) { int xhi = x & - BM_WORDBITS; - int xlo = x & (BM_WORDBITS - 1); /* = x % BM_WORDBITS */ + int xlo = x & ( BM_WORDBITS - 1 ); /* = x % BM_WORDBITS */ int i; - if( xhipriv->len <= 0 ) /* a path of length 0 is silly, but legal */ + if( p->priv->len <= 0 ) { + /* a path of length 0 is silly, but legal */ return; } @@ -185,7 +191,7 @@ static void xor_path( potrace_bitmap_t* bm, path_t* p ) xa = p->priv->pt[0].x & - BM_WORDBITS; - for( k = 0; kpriv->len; k++ ) + for( k = 0; k < p->priv->len; k++ ) { x = p->priv->pt[k].x; y = p->priv->pt[k].y; @@ -212,7 +218,7 @@ static void setbbox_path( bbox_t* bbox, path_t* p ) bbox->x0 = INT_MAX; bbox->x1 = 0; - for( k = 0; kpriv->len; k++ ) + for( k = 0; k < p->priv->len; k++ ) { x = p->priv->pt[k].x; y = p->priv->pt[k].y; @@ -248,7 +254,8 @@ static void setbbox_path( bbox_t* bbox, path_t* p ) * of turnpolicies. */ static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int turnpolicy ) { - int x, y, dirx, diry, len, size, area; + int x, y, dirx, diry, len, size; + uint64_t area; int c, d, tmp; point_t* pt, * pt1; path_t* p = NULL; @@ -265,11 +272,11 @@ static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int tur while( 1 ) { /* add point to path */ - if( len>=size ) + if( len >= size ) { size += 100; - size = (int) (1.3 * size); - pt1 = (point_t*) realloc( pt, size * sizeof(point_t) ); + size = (int) ( 1.3 * size ); + pt1 = (point_t*) realloc( pt, size * sizeof( point_t ) ); if( !pt1 ) { @@ -289,20 +296,21 @@ static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int tur area += x * diry; /* path complete? */ - if( x==x0 && y==y0 ) + if( x == x0 && y == y0 ) { break; } /* determine next direction */ - c = BM_GET( bm, x + (dirx + diry - 1) / 2, y + (diry - dirx - 1) / 2 ); - d = BM_GET( bm, x + (dirx - diry - 1) / 2, y + (diry + dirx - 1) / 2 ); + c = BM_GET( bm, x + ( dirx + diry - 1 ) / 2, y + ( diry - dirx - 1 ) / 2 ); + d = BM_GET( bm, x + ( dirx - diry - 1 ) / 2, y + ( diry + dirx - 1 ) / 2 ); - if( c && !d ) /* ambiguous turn */ + if( c && !d ) { + /* ambiguous turn */ if( turnpolicy == POTRACE_TURNPOLICY_RIGHT - || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+') - || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-') + || ( turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+' ) + || ( turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-' ) || ( turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand( x, y ) ) || ( turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority( bm, x, y ) ) || ( turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority( bm, x, y ) ) ) @@ -318,14 +326,16 @@ static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int tur diry = tmp; } } - else if( c ) /* right turn */ + else if( c ) { + /* right turn */ tmp = dirx; dirx = diry; diry = -tmp; } - else if( !d ) /* left turn */ + else if( !d ) { + /* left turn */ tmp = dirx; dirx = -diry; diry = tmp; @@ -342,7 +352,7 @@ static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int tur p->priv->pt = pt; p->priv->len = len; - p->area = area; + p->area = area <= INT_MAX ? area : INT_MAX; /* avoid overflow */ p->sign = sign; return p; @@ -519,11 +529,11 @@ static int findnext( potrace_bitmap_t* bm, int* xp, int* yp ) int y; int x0; - x0 = (*xp) & ~(BM_WORDBITS - 1); + x0 = ( *xp ) & ~( BM_WORDBITS - 1 ); - for( y = *yp; y>=0; y-- ) + for( y = *yp; y >= 0; y-- ) { - for( x = x0; xw; x += BM_WORDBITS ) + for( x = x0; x < bm->w && x >= 0; x += (unsigned) BM_WORDBITS ) { if( *bm_index( bm, x, y ) ) { @@ -552,9 +562,7 @@ static int findnext( potrace_bitmap_t* bm, int* xp, int* yp ) * in. Returns 0 on success with plistp set, or -1 on error with errno * set. */ -int bm_to_pathlist( const potrace_bitmap_t* bm, - path_t** plistp, - const potrace_param_t* param, +int bm_to_pathlist( const potrace_bitmap_t* bm, path_t** plistp, const potrace_param_t* param, progress_t* progress ) { int x; @@ -588,7 +596,7 @@ int bm_to_pathlist( const potrace_bitmap_t* bm, /* calculate the path */ p = findpath( bm1, x, y + 1, sign, param->turnpolicy ); - if( p==NULL ) + if( p == NULL ) { goto error; } @@ -606,8 +614,9 @@ int bm_to_pathlist( const potrace_bitmap_t* bm, list_insert_beforehook( p, plist_hook ); } - if( bm1->h > 0 ) /* to be sure */ + if( bm1->h > 0 ) { + /* to be sure */ progress_update( 1 - y / (double) bm1->h, progress ); } } diff --git a/potrace/decompose.h b/potrace/decompose.h index f1d940f41d..5a1113c152 100644 --- a/potrace/decompose.h +++ b/potrace/decompose.h @@ -1,18 +1,15 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ - #ifndef DECOMPOSE_H #define DECOMPOSE_H +#include "curve.h" #include "potracelib.h" #include "progress.h" -#include "curve.h" -int bm_to_pathlist( const potrace_bitmap_t* bm, - path_t** plistp, - const potrace_param_t* param, +int bm_to_pathlist( const potrace_bitmap_t* bm, path_t** plistp, const potrace_param_t* param, progress_t* progress ); #endif /* DECOMPOSE_H */ diff --git a/potrace/greymap.cpp b/potrace/greymap.cpp index 08411ff4eb..88e7641f42 100644 --- a/potrace/greymap.cpp +++ b/potrace/greymap.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -10,40 +10,92 @@ #include #endif +#include +#include +#include #include #include -#include -#include -#include -#include "greymap.h" #include "bitops.h" +#include "greymap.h" -#define INTBITS ( 8 * sizeof(int) ) +#define INTBITS ( 8 * sizeof( int ) ) -#define mod( a, n ) ( (a)>=(n) ? (a) % (n) : (a)>=0 ? (a) : (n) - 1 - ( -1 - (a) ) % (n) ) +#define mod( a, n ) \ + ( ( a ) >= ( n ) ? ( a ) % ( n ) : ( a ) >= 0 ? ( a ) : (n) - 1 - ( -1 - ( a ) ) % ( n ) ) static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic ); static int gm_readbody_bmp( FILE* f, greymap_t** gmp ); +#define TRY( x ) \ + if( x ) \ + goto try_error +#define TRY_EOF( x ) \ + if( x ) \ + goto eof +#define TRY_STD( x ) \ + if( x ) \ + goto std_error + /* ---------------------------------------------------------------------- */ /* basic greymap routines */ -/* return new un-initialized greymap. NULL with errno on error. +/* calculate the size, in bytes, required for the data area of a + * greymap of the given dy and h. Assume h >= 0. Return -1 if the size + * does not fit into the ptrdiff_t type. */ +static inline ptrdiff_t getsize( int dy, int h ) +{ + ptrdiff_t size; + + if( dy < 0 ) + { + dy = -dy; + } + + size = (ptrdiff_t) dy * (ptrdiff_t) h * (ptrdiff_t) sizeof( gm_sample_t ); + + /* check for overflow error */ + if( size < 0 || ( h != 0 && dy != 0 && size / h / dy != sizeof( gm_sample_t ) ) ) + { + return -1; + } + + return size; +} + + +/* return the size, in bytes, of the data area of the greymap. Return + * -1 if the size does not fit into the ptrdiff_t type; however, this + * cannot happen if the bitmap is well-formed, i.e., if created with + * gm_new or gm_dup. */ +static inline ptrdiff_t gm_size( const greymap_t* gm ) +{ + return getsize( gm->dy, gm->h ); +} + + +/* return new greymap initialized to 0. NULL with errno on error. * Assumes w, h >= 0. */ greymap_t* gm_new( int w, int h ) { - greymap_t* gm; - ptrdiff_t size = (ptrdiff_t) w * (ptrdiff_t) h * (ptrdiff_t) sizeof(signed short int); + greymap_t* gm; + int dy = w; + ptrdiff_t size; - /* check for overflow error */ - if( size < 0 || size / w / h != sizeof(signed short int) ) + size = getsize( dy, h ); + + if( size < 0 ) { errno = ENOMEM; return NULL; } - gm = (greymap_t*) malloc( sizeof(greymap_t) ); + if( size == 0 ) + { + size = 1; /* make surecmalloc() doesn't return NULL */ + } + + gm = (greymap_t*) malloc( sizeof( greymap_t ) ); if( !gm ) { @@ -52,14 +104,16 @@ greymap_t* gm_new( int w, int h ) gm->w = w; gm->h = h; - gm->map = (signed short int*) malloc( size ); + gm->dy = dy; + gm->base = (gm_sample_t*) calloc( 1, size ); - if( !gm->map ) + if( !gm->base ) { free( gm ); return NULL; } + gm->map = gm->base; return gm; } @@ -69,7 +123,7 @@ void gm_free( greymap_t* gm ) { if( gm ) { - free( gm->map ); + free( gm->base ); } free( gm ); @@ -80,13 +134,19 @@ void gm_free( greymap_t* gm ) greymap_t* gm_dup( greymap_t* gm ) { greymap_t* gm1 = gm_new( gm->w, gm->h ); + int y; if( !gm1 ) { return NULL; } - memcpy( gm1->map, gm->map, gm->w * gm->h * sizeof(signed short int) ); + for( y = 0; y < gm->h; y++ ) + { + memcpy( gm_scanline( gm1, y ), gm_scanline( gm, y ), + (size_t) gm1->dy * sizeof( gm_sample_t ) ); + } + return gm1; } @@ -94,22 +154,101 @@ greymap_t* gm_dup( greymap_t* gm ) /* clear the given greymap to color b. */ void gm_clear( greymap_t* gm, int b ) { - int i; + ptrdiff_t size = gm_size( gm ); + int x, y; - if( b==0 ) + if( b == 0 ) { - memset( gm->map, 0, gm->w * gm->h * sizeof(signed short int) ); + memset( gm->base, 0, size ); } else { - for( i = 0; iw * gm->h; i++ ) + for( y = 0; y < gm->h; y++ ) { - gm->map[i] = b; + for( x = 0; x < gm->w; x++ ) + { + GM_UPUT( gm, x, y, b ); + } } } } +/* turn the given greymap upside down. This does not move the pixel + * data or change the base address. */ +static inline void gm_flip( greymap_t* gm ) +{ + int dy = gm->dy; + + if( gm->h == 0 || gm->h == 1 ) + { + return; + } + + gm->map = gm_scanline( gm, gm->h - 1 ); + gm->dy = -dy; +} + + +/* resize the greymap to the given new height. The pixel data remains + * bottom-aligned (truncated at the top) when dy >= 0 and top-aligned + * (truncated at the bottom) when dy < 0. Return 0 on success, or 1 on + * error with errno set. If the new height is <= the old one, no error + * should occur. If the new height is larger, the additional pixel + * data is *not* initialized. */ +static inline int gm_resize( greymap_t* gm, int h ) +{ + int dy = gm->dy; + ptrdiff_t newsize; + gm_sample_t* newbase; + + if( dy < 0 ) + { + gm_flip( gm ); + } + + newsize = getsize( dy, h ); + + if( newsize < 0 ) + { + errno = ENOMEM; + goto error; + } + + if( newsize == 0 ) + { + newsize = 1; /* make sure realloc() doesn't return NULL */ + } + + newbase = (gm_sample_t*) realloc( gm->base, newsize ); + + if( newbase == NULL ) + { + goto error; + } + + gm->base = newbase; + gm->map = newbase; + gm->h = h; + + if( dy < 0 ) + { + gm_flip( gm ); + } + + return 0; + +error: + + if( dy < 0 ) + { + gm_flip( gm ); + } + + return 1; +} + + /* ---------------------------------------------------------------------- */ /* routines for reading pnm streams */ @@ -123,13 +262,13 @@ static int fgetc_ws( FILE* f ) { c = fgetc( f ); - if( c=='#' ) + if( c == '#' ) { while( 1 ) { c = fgetc( f ); - if( c=='\n' || c==EOF ) + if( c == '\n' || c == EOF ) { break; } @@ -137,7 +276,7 @@ static int fgetc_ws( FILE* f ) } /* space, tab, line feed, carriage return, form-feed */ - if( c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12 ) + if( c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != 12 ) { return c; } @@ -160,12 +299,12 @@ static int readnum( FILE* f ) { c = fgetc_ws( f ); - if( c==EOF ) + if( c == EOF ) { return -1; } - if( c>='0' && c<='9' ) + if( c >= '0' && c <= '9' ) { break; } @@ -178,12 +317,12 @@ static int readnum( FILE* f ) { c = fgetc( f ); - if( c==EOF ) + if( c == EOF ) { break; } - if( c<'0' || c>'9' ) + if( c < '0' || c > '9' ) { ungetc( c, f ); break; @@ -209,12 +348,12 @@ static int readbit( FILE* f ) { c = fgetc_ws( f ); - if( c==EOF ) + if( c == EOF ) { return -1; } - if( c>='0' && c<='1' ) + if( c >= '0' && c <= '1' ) { break; } @@ -277,21 +416,23 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic ) { greymap_t* gm; int x, y, i, j, b, b1, sum; - int bpr; /* bytes per row (as opposed to 4*gm->c) */ + int bpr; /* bytes per row (as opposed to 4*gm->c) */ int w, h, max; + int realheight; /* in case of incomplete file, keeps track of how + * many scan lines actually contain data */ gm = NULL; w = readnum( f ); - if( w<0 ) + if( w < 0 ) { goto format_error; } h = readnum( f ); - if( h<0 ) + if( h < 0 ) { goto format_error; } @@ -301,11 +442,10 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic ) if( !gm ) { - return -1; + goto std_error; } - /* zero it out */ - gm_clear( gm, 0 ); + realheight = 0; switch( magic ) { @@ -316,13 +456,15 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic ) case '1': /* read P1 format: PBM ascii */ - for( y = h - 1; y>=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=0; y-- ) + for( y = 0; y < h; y++ ) { - for( i = 0; i> j) ? 0 : 255 ); + GM_PUT( gm, i * 8 + j, y, b & ( 0x80 >> j ) ? 0 : 255 ); } } } @@ -431,33 +579,35 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic ) max = readnum( f ); - if( max<1 ) + if( max < 1 ) { goto format_error; } b = fgetc( f ); /* read single white-space character after max */ - if( b==EOF ) + if( b == EOF ) { goto format_error; } - for( y = h - 1; y>=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=256 ) + if( max >= 256 ) { b <<= 8; b1 = fgetc( f ); - if( b1==EOF ) + if( b1 == EOF ) goto eof; b |= b1; @@ -474,39 +624,41 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic ) max = readnum( f ); - if( max<1 ) + if( max < 1 ) { goto format_error; } b = fgetc( f ); /* read single white-space character after max */ - if( b==EOF ) + if( b == EOF ) { goto format_error; } - for( y = h - 1; y>=0; y-- ) + for( y = 0; y < h; y++ ) { - for( x = 0; x=256 ) + if( max >= 256 ) { b <<= 8; b1 = fgetc( f ); - if( b1==EOF ) + if( b1 == EOF ) goto eof; b |= b1; @@ -515,17 +667,20 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic ) sum += b; } - GM_UPUT( gm, x, y, sum * (255 / 3) / max ); + GM_UPUT( gm, x, y, sum * ( 255 / 3 ) / max ); } } break; } + gm_flip( gm ); *gmp = gm; return 0; eof: + TRY_STD( gm_resize( gm, realheight ) ); + gm_flip( gm ); *gmp = gm; return 1; @@ -546,6 +701,10 @@ format_error: } return -2; + +std_error: + gm_free( gm ); + return -1; } @@ -558,22 +717,22 @@ struct bmp_info_s unsigned int reserved; unsigned int DataOffset; unsigned int InfoSize; - unsigned int w; /* width */ - unsigned int h; /* height */ + unsigned int w; /* width */ + unsigned int h; /* height */ unsigned int Planes; - unsigned int bits; /* bits per sample */ - unsigned int comp; /* compression mode */ + unsigned int bits; /* bits per sample */ + unsigned int comp; /* compression mode */ unsigned int ImageSize; unsigned int XpixelsPerM; unsigned int YpixelsPerM; - unsigned int ncolors; /* number of colors in palette */ + unsigned int ncolors; /* number of colors in palette */ unsigned int ColorsImportant; unsigned int RedMask; unsigned int GreenMask; unsigned int BlueMask; unsigned int AlphaMask; - unsigned int ctbits; /* sample size for color table */ - int topdown; /* top-down mode? */ + unsigned int ctbits; /* sample size for color table */ + int topdown; /* top-down mode? */ }; typedef struct bmp_info_s bmp_info_t; @@ -590,16 +749,16 @@ static int bmp_readint( FILE* f, int n, unsigned int* p ) unsigned int sum = 0; int b; - for( i = 0; i= 108 ) /* V4 and V5 bitmaps */ + if( bmpinfo.InfoSize >= 108 ) { + /* V4 and V5 bitmaps */ TRY( bmp_readint( f, 4, &bmpinfo.RedMask ) ); TRY( bmp_readint( f, 4, &bmpinfo.GreenMask ) ); TRY( bmp_readint( f, 4, &bmpinfo.BlueMask ) ); @@ -735,7 +892,7 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) if( bmpinfo.h > 0x7fffffff ) { - bmpinfo.h = (-bmpinfo.h) & 0xffffffff; + bmpinfo.h = ( -bmpinfo.h ) & 0xffffffff; bmpinfo.topdown = 1; } else @@ -771,6 +928,11 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) goto format_error; } + if( bmpinfo.comp > 3 || bmpinfo.bits > 32 ) + { + goto format_error; + } + /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */ TRY( bmp_forward( f, 14 + bmpinfo.InfoSize ) ); @@ -780,7 +942,7 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) goto format_error; /* can't handle planes */ } - if( bmpinfo.ncolors == 0 ) + if( bmpinfo.ncolors == 0 && bmpinfo.bits <= 8 ) { bmpinfo.ncolors = 1 << bmpinfo.bits; } @@ -788,7 +950,7 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) /* color table, present only if bmpinfo.bits <= 8. */ if( bmpinfo.bits <= 8 ) { - coltable = (int*) calloc( bmpinfo.ncolors, sizeof(int) ); + coltable = (int*) calloc( bmpinfo.ncolors, sizeof( int ) ); if( !coltable ) { @@ -797,17 +959,18 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) /* NOTE: since we are reading a greymap, we can immediately convert * the color table entries to grey values. */ - for( i = 0; i> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff); + c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff ); coltable[i] = c / 3; } } /* forward to data */ - if( bmpinfo.InfoSize != 12 ) /* not old OS/2 format */ + if( bmpinfo.InfoSize != 12 ) { + /* not old OS/2 format */ TRY( bmp_forward( f, bmpinfo.DataOffset ) ); } @@ -819,30 +982,28 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) goto std_error; } - /* zero it out */ - gm_clear( gm, 0 ); + realheight = 0; switch( bmpinfo.bits + 0x100 * bmpinfo.comp ) { default: - goto format_error; - break; + goto format_error; break; case 0x001: /* monochrome palette */ /* raster data */ - for( y = 0; y> j) ? coltable[1] : coltable[0] ); + GM_PUT( gm, i * 8 + j, y, b & ( 0x80 >> j ) ? COLTABLE( 1 ) : COLTABLE( 0 ) ); } } @@ -859,25 +1020,26 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) case 0x007: case 0x008: - for( y = 0; y> (INTBITS - bmpinfo.bits); + b = bitbuf >> ( INTBITS - bmpinfo.bits ); bitbuf <<= bmpinfo.bits; n -= bmpinfo.bits; - GM_UPUT( gm, x, ycorr( y ), coltable[b] ); + GM_UPUT( gm, x, y, COLTABLE( b ) ); } TRY( bmp_pad( f ) ); @@ -895,15 +1057,16 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) case 0x018: /* 24-bit encoding */ case 0x020: /* 32-bit encoding */ - for( y = 0; y> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff); - GM_UPUT( gm, x, ycorr( y ), c / 3 ); + c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff ); + GM_UPUT( gm, x, y, c / 3 ); } TRY( bmp_pad( f ) ); @@ -916,17 +1079,18 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) greenshift = lobit( bmpinfo.GreenMask ); blueshift = lobit( bmpinfo.BlueMask ); - for( y = 0; y> redshift ) + - ( (c & bmpinfo.GreenMask) >> greenshift ) + - ( (c & bmpinfo.BlueMask) >> blueshift ); - GM_UPUT( gm, x, ycorr( y ), c / 3 ); + c = ( ( c & bmpinfo.RedMask ) >> redshift ) + + ( ( c & bmpinfo.GreenMask ) >> greenshift ) + + ( ( c & bmpinfo.BlueMask ) >> blueshift ); + GM_UPUT( gm, x, y, c / 3 ); } TRY( bmp_pad( f ) ); @@ -943,26 +1107,27 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */ TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */ - if( b>0 ) + if( b > 0 ) { /* repeat count */ - col[0] = coltable[(c >> 4) & 0xf]; - col[1] = coltable[c & 0xf]; + col[0] = COLTABLE( ( c >> 4 ) & 0xf ); + col[1] = COLTABLE( c & 0xf ); - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - GM_UPUT( gm, x, ycorr( y ), col[i & 1] ); + realheight = y + 1; + GM_PUT( gm, x, y, col[i & 1] ); x++; } } @@ -988,29 +1153,30 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) else { /* verbatim segment */ - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - GM_PUT( gm, x, ycorr( y ), coltable[( b >> ( 4 - 4 * (i & 1) ) ) & 0xf] ); + realheight = y + 1; + GM_PUT( gm, x, y, COLTABLE( ( b >> ( 4 - 4 * ( i & 1 ) ) ) & 0xf ) ); x++; } - if( (c + 1) & 2 ) + if( ( c + 1 ) & 2 ) { /* pad to 16-bit boundary */ TRY_EOF( bmp_readint( f, 1, &b ) ); @@ -1029,23 +1195,24 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */ TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */ - if( b>0 ) + if( b > 0 ) { /* repeat count */ - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - GM_UPUT( gm, x, ycorr( y ), coltable[c] ); + realheight = y + 1; + GM_PUT( gm, x, y, COLTABLE( c ) ); x++; } } @@ -1071,22 +1238,23 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) else { /* verbatim segment */ - for( i = 0; i=bmpinfo.w ) + if( x >= bmpinfo.w ) { x = 0; y++; } - if( y>=bmpinfo.h ) + if( x >= bmpinfo.w || y >= bmpinfo.h ) { break; } - GM_PUT( gm, x, ycorr( y ), coltable[b] ); + realheight = y + 1; + GM_PUT( gm, x, y, COLTABLE( b ) ); x++; } @@ -1106,18 +1274,31 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp ) bmp_forward( f, bmpinfo.FileSize ); free( coltable ); + + if( bmpinfo.topdown ) + { + gm_flip( gm ); + } + *gmp = gm; return 0; eof: + TRY_STD( gm_resize( gm, realheight ) ); free( coltable ); + + if( bmpinfo.topdown ) + { + gm_flip( gm ); + } + *gmp = gm; return 1; format_error: try_error: free( coltable ); - free( gm ); + gm_free( gm ); if( !gm_read_error ) { @@ -1128,7 +1309,7 @@ try_error: std_error: free( coltable ); - free( gm ); + gm_free( gm ); return -1; } @@ -1141,7 +1322,7 @@ std_error: * if any (set to 2.2 if the image is to look optimal on a CRT monitor, * 2.8 for LCD). Set to 1.0 for no gamma correction */ -int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, double gamma ) +int gm_writepgm( FILE* f, greymap_t* gm, const char* comment, int raw, int mode, double gamma ) { int x, y, v; int gammatable[256]; @@ -1151,14 +1332,14 @@ int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, doubl { gammatable[0] = 0; - for( v = 1; v<256; v++ ) + for( v = 1; v < 256; v++ ) { - gammatable[v] = (int) (255 * exp( log( v / 255.0 ) / gamma ) + 0.5); + gammatable[v] = (int) ( 255 * exp( log( v / 255.0 ) / gamma ) + 0.5 ); } } else { - for( v = 0; v<256; v++ ) + for( v = 0; v < 256; v++ ) { gammatable[v] = v; } @@ -1173,9 +1354,9 @@ int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, doubl fprintf( f, "%d %d 255\n", gm->w, gm->h ); - for( y = gm->h - 1; y>=0; y-- ) + for( y = gm->h - 1; y >= 0; y-- ) { - for( x = 0; xw; x++ ) + for( x = 0; x < gm->w; x++ ) { v = GM_UGET( gm, x, y ); @@ -1254,18 +1435,18 @@ int gm_print( FILE* f, greymap_t* gm ) int sw, sh; sw = gm->w < 79 ? gm->w : 79; - sh = gm->w < 79 ? gm->h : gm->h * sw * 44 / (79 * gm->w); + sh = gm->w < 79 ? gm->h : gm->h * sw * 44 / ( 79 * gm->w ); - for( yy = sh - 1; yy>=0; yy-- ) + for( yy = sh - 1; yy >= 0; yy-- ) { - for( xx = 0; xxw / sw; x<(xx + 1) * gm->w / sw; x++ ) + for( x = xx * gm->w / sw; x < ( xx + 1 ) * gm->w / sw; x++ ) { - for( y = yy * gm->h / sh; y<(yy + 1) * gm->h / sh; y++ ) + for( y = yy * gm->h / sh; y < ( yy + 1 ) * gm->h / sh; y++ ) { d += GM_GET( gm, x, y ); t += 256; diff --git a/potrace/greymap.h b/potrace/greymap.h index 2505232335..7c1992d89c 100644 --- a/potrace/greymap.h +++ b/potrace/greymap.h @@ -1,44 +1,50 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ - #ifndef GREYMAP_H #define GREYMAP_H +#include #include #include -#include + +/* type for greymap samples */ +typedef signed short int gm_sample_t; /* internal format for greymaps. Note: in this format, rows are * ordered from bottom to top. The pixels in each row are given from * left to right. */ - struct greymap_s { - int w; /* width, in pixels */ - int h; /* height, in pixels */ - signed short int* map; /* raw data, w*h values */ + int w; /* width, in pixels */ + int h; /* height, in pixels */ + int dy; /* offset between scanlines (in samples); + * can be negative */ + gm_sample_t* base; /* root of allocated data */ + gm_sample_t* map; /* points to the lower left pixel */ }; typedef struct greymap_s greymap_t; /* macros for accessing pixel at index (x,y). Note that the origin is * in the *lower* left corner. U* macros omit the bounds check. */ -#define gm_index( gm, x, y ) (&(gm)->map[(x) + (y) * (ptrdiff_t) (gm)->w]) -#define gm_safe( gm, x, \ - y ) ( (int) (x)>=0 && (int) (x)<(gm)->w && (int) (y)>=0 \ - && (int) (y)<(gm)->h ) -#define gm_bound( x, m ) ( (x)<0 ? 0 : (x)>=(m) ? (m) - 1 : (x) ) +#define gm_scanline( gm, y ) ( ( gm )->map + (ptrdiff_t) ( y ) * (ptrdiff_t) ( gm )->dy ) +#define gm_index( gm, x, y ) ( gm_scanline( gm, y ) + ( x ) ) +#define gm_safe( gm, x, y ) \ + ( (int) ( x ) >= 0 && (int) ( x ) < ( gm )->w && (int) ( y ) >= 0 && (int) ( y ) < ( gm )->h ) +#define gm_bound( x, m ) ( ( x ) < 0 ? 0 : ( x ) >= ( m ) ? (m) - 1 : ( x ) ) #define GM_UGET( gm, x, y ) ( *gm_index( gm, x, y ) ) -#define GM_UINC( gm, x, y, b ) ( *gm_index( gm, x, y ) += (short int) (b) ) +#define GM_UINC( gm, x, y, b ) ( *gm_index( gm, x, y ) += (gm_sample_t) ( b ) ) #define GM_UINV( gm, x, y ) ( *gm_index( gm, x, y ) = 255 - *gm_index( gm, x, y ) ) -#define GM_UPUT( gm, x, y, b ) ( *gm_index( gm, x, y ) = (short int) (b) ) -#define GM_GET( gm, x, y ) (gm_safe( gm, x, y ) ? GM_UGET( gm, x, y ) : 0) -#define GM_INC( gm, x, y, b ) (gm_safe( gm, x, y ) ? GM_UINC( gm, x, y, b ) : 0) -#define GM_INV( gm, x, y ) (gm_safe( gm, x, y ) ? GM_UINV( gm, x, y ) : 0) -#define GM_PUT( gm, x, y, b ) (gm_safe( gm, x, y ) ? GM_UPUT( gm, x, y, b ) : 0) -#define GM_BGET( gm, x, y ) GM_UGET( gm, gm_bound( x, gm->w ), gm_bound( y, gm->h ) ) +#define GM_UPUT( gm, x, y, b ) ( *gm_index( gm, x, y ) = (gm_sample_t) ( b ) ) +#define GM_GET( gm, x, y ) ( gm_safe( gm, x, y ) ? GM_UGET( gm, x, y ) : 0 ) +#define GM_INC( gm, x, y, b ) ( gm_safe( gm, x, y ) ? GM_UINC( gm, x, y, b ) : 0 ) +#define GM_INV( gm, x, y ) ( gm_safe( gm, x, y ) ? GM_UINV( gm, x, y ) : 0 ) +#define GM_PUT( gm, x, y, b ) ( gm_safe( gm, x, y ) ? GM_UPUT( gm, x, y, b ) : 0 ) +#define GM_BGET( gm, x, y ) \ + ( ( gm )->w == 0 || ( gm )->h == 0 ? 0 : GM_UGET( gm, gm_bound( x, ( gm )->w ), \ + gm_bound( y, ( gm )->h ) ) ) /* modes for cutting off out-of-range values. The following names * refer to winding numbers. I.e., make a pixel black if winding @@ -56,7 +62,12 @@ greymap_t* gm_dup( greymap_t* gm ); void gm_free( greymap_t* gm ); void gm_clear( greymap_t* gm, int b ); int gm_read( FILE* f, greymap_t** gmp ); -int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, double gamma ); -int gm_print( FILE* f, greymap_t* gm ); +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 ); #endif /* GREYMAP_H */ diff --git a/potrace/lists.h b/potrace/lists.h index 98de9c2a1e..430a30975e 100644 --- a/potrace/lists.h +++ b/potrace/lists.h @@ -1,8 +1,7 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ - #ifndef _PS_LISTS_H #define _PS_LISTS_H @@ -31,148 +30,168 @@ * such as "if (...) macro(...); else ...". If we didn't use this obscure * trick, we'd have to omit the ";" in such cases. */ -#define MACRO_BEGIN do { -#define MACRO_END } \ +#define MACRO_BEGIN \ + do \ + { +#define MACRO_END \ + } \ while( 0 ) /* ---------------------------------------------------------------------- */ /* macros for singly-linked lists */ /* traverse list. At the end, elt is set to NULL. */ -#define list_forall( elt, list ) for( elt = list; elt!=NULL; elt = elt->next ) +#define list_forall( elt, list ) for( elt = list; elt != NULL; elt = elt->next ) /* set elt to the first element of list satisfying boolean condition * c, or NULL if not found */ -#define list_find( elt, list, c ) \ +#define list_find( elt, list, c ) \ MACRO_BEGIN list_forall( elt, list ) if( c ) \ break; \ MACRO_END /* like forall, except also set hook for elt. */ #define list_forall2( elt, list, hook ) \ - for( elt = list, hook = &list; elt!=NULL; hook = &elt->next, elt = elt->next ) + for( elt = list, hook = &list; elt != NULL; hook = &elt->next, elt = elt->next ) /* same as list_find, except also set hook for elt. */ -#define list_find2( elt, list, c, hook ) \ +#define list_find2( elt, list, c, hook ) \ MACRO_BEGIN list_forall2( elt, list, hook ) if( c ) \ break; \ MACRO_END /* same, except only use hook. */ -#define _list_forall_hook( list, hook ) \ - for( hook = &list; *hook!=NULL; hook = &(*hook)->next ) +#define _list_forall_hook( list, hook ) for( hook = &list; *hook != NULL; hook = &( *hook )->next ) /* same, except only use hook. Note: c may only refer to *hook, not elt. */ -#define _list_find_hook( list, c, hook ) \ +#define _list_find_hook( list, c, hook ) \ MACRO_BEGIN _list_forall_hook( list, hook ) if( c ) \ break; \ MACRO_END /* insert element after hook */ #define list_insert_athook( elt, hook ) \ - MACRO_BEGIN elt->next = *hook; *hook = elt; MACRO_END + MACRO_BEGIN elt->next = *hook; \ + *hook = elt; \ + MACRO_END /* insert element before hook */ #define list_insert_beforehook( elt, hook ) \ - MACRO_BEGIN elt->next = *hook; *hook = elt; hook = &elt->next; MACRO_END + MACRO_BEGIN elt->next = *hook; \ + *hook = elt; \ + hook = &elt->next; \ + MACRO_END /* unlink element after hook, let elt be unlinked element, or NULL. * hook remains. */ #define list_unlink_athook( list, elt, hook ) \ - MACRO_BEGIN \ - elt = hook ? *hook : NULL; if( elt ) { *hook = elt->next; elt->next = NULL; } \ + MACRO_BEGIN \ + elt = hook ? *hook : NULL; \ + if( elt ) \ + { \ + *hook = elt->next; \ + elt->next = NULL; \ + } \ MACRO_END /* unlink the specific element, if it is in the list. Otherwise, set * elt to NULL */ -#define list_unlink( listtype, list, elt ) \ - MACRO_BEGIN \ - listtype * *_hook; \ - _list_find_hook( list, *_hook==elt, _hook ); \ - list_unlink_athook( list, elt, _hook ); \ +#define list_unlink( listtype, list, elt ) \ + MACRO_BEGIN \ + listtype * *_hook; \ + _list_find_hook( list, *_hook == elt, _hook ); \ + list_unlink_athook( list, elt, _hook ); \ MACRO_END /* prepend elt to list */ #define list_prepend( list, elt ) \ - MACRO_BEGIN elt->next = list; list = elt; MACRO_END + MACRO_BEGIN elt->next = list; \ + list = elt; \ + MACRO_END /* append elt to list. */ -#define list_append( listtype, list, elt ) \ - MACRO_BEGIN \ - listtype * *_hook; \ - _list_forall_hook( list, _hook ) {} \ - list_insert_athook( elt, _hook ); \ +#define list_append( listtype, list, elt ) \ + MACRO_BEGIN \ + listtype * *_hook; \ + _list_forall_hook( list, _hook ) \ + { \ + } \ + list_insert_athook( elt, _hook ); \ MACRO_END /* unlink the first element that satisfies the condition. */ -#define list_unlink_cond( listtype, list, elt, c ) \ - MACRO_BEGIN \ - listtype * *_hook; \ - list_find2( elt, list, c, _hook ); \ - list_unlink_athook( list, elt, _hook ); \ +#define list_unlink_cond( listtype, list, elt, c ) \ + MACRO_BEGIN \ + listtype * *_hook; \ + list_find2( elt, list, c, _hook ); \ + list_unlink_athook( list, elt, _hook ); \ MACRO_END /* let elt be the nth element of the list, starting to count from 0. * Return NULL if out of bounds. */ -#define list_nth( elt, list, n ) \ - MACRO_BEGIN \ - int _x; /* only evaluate n once */ \ - for( _x = (n), elt = list; _x && elt; _x--, elt = elt->next ) {} \ +#define list_nth( elt, list, n ) \ + MACRO_BEGIN \ + int _x; /* only evaluate n once */ \ + for( _x = ( n ), elt = list; _x && elt; _x--, elt = elt->next ) \ + { \ + } \ MACRO_END /* let elt be the nth element of the list, starting to count from 0. * Return NULL if out of bounds. */ -#define list_nth_hook( elt, list, n, hook ) \ - MACRO_BEGIN \ - int _x; /* only evaluate n once */ \ - for( _x = (n), elt = list, hook = &list; _x && elt; \ - _x--, hook = &elt->next, elt = elt->next ) {} \ +#define list_nth_hook( elt, list, n, hook ) \ + MACRO_BEGIN \ + int _x; /* only evaluate n once */ \ + for( _x = ( n ), elt = list, hook = &list; _x && elt; \ + _x--, hook = &elt->next, elt = elt->next ) \ + { \ + } \ MACRO_END /* set n to the length of the list */ -#define list_length( listtype, list, n ) \ - MACRO_BEGIN \ - listtype * _elt; \ - n = 0; \ - list_forall( _elt, list ) \ - n++; \ +#define list_length( listtype, list, n ) \ + MACRO_BEGIN \ + listtype * _elt; \ + n = 0; \ + list_forall( _elt, list ) n++; \ MACRO_END /* set n to the index of the first element satisfying cond, or -1 if * none found. Also set elt to the element, or NULL if none found. */ -#define list_index( list, n, elt, c ) \ - MACRO_BEGIN \ - n = 0; \ - list_forall( elt, list ) { \ - if( c ) \ +#define list_index( list, n, elt, c ) \ + MACRO_BEGIN \ + n = 0; \ + list_forall( elt, list ) \ + { \ + if( c ) \ break; \ - n++; \ - } \ - if( !elt ) \ - n = -1; \ + n++; \ + } \ + if( !elt ) \ + n = -1; \ MACRO_END /* set n to the number of elements in the list that satisfy condition c */ -#define list_count( list, n, elt, c ) \ - MACRO_BEGIN \ - n = 0; \ - list_forall( elt, list ) { \ - if( c ) \ +#define list_count( list, n, elt, c ) \ + MACRO_BEGIN \ + n = 0; \ + list_forall( elt, list ) \ + { \ + if( c ) \ n++; \ - } \ + } \ MACRO_END /* let elt be each element of the list, unlinked. At the end, set list=NULL. */ #define list_forall_unlink( elt, list ) \ - for( elt = list; elt ? (list = elt->next, elt->next = NULL), 1 : 0; elt = list ) + for( elt = list; elt ? ( list = elt->next, elt->next = NULL ), 1 : 0; elt = list ) /* reverse a list (efficient) */ -#define list_reverse( listtype, list ) \ - MACRO_BEGIN \ - listtype * _list1 = NULL, *elt; \ - list_forall_unlink( elt, list ) \ - list_prepend( _list1, elt ); \ - list = _list1; \ +#define list_reverse( listtype, list ) \ + MACRO_BEGIN \ + listtype * _list1 = NULL, *elt; \ + list_forall_unlink( elt, list ) list_prepend( _list1, elt ); \ + list = _list1; \ MACRO_END /* insert the element ELT just before the first element TMP of the @@ -186,10 +205,10 @@ * Note: it is much more efficient to construct a list with * list_prepend and then order it with list_merge_sort, than to * construct it with list_insert_ordered. */ -#define list_insert_ordered( listtype, list, elt, tmp, cond ) \ - MACRO_BEGIN \ - listtype * *_hook; \ - _list_find_hook( list, ( tmp = *_hook, (cond) ), _hook ); \ +#define list_insert_ordered( listtype, list, elt, tmp, cond ) \ + MACRO_BEGIN \ + listtype * *_hook; \ + _list_find_hook( list, ( tmp = *_hook, ( cond ) ), _hook ); \ list_insert_athook( elt, _hook ); \ MACRO_END @@ -200,12 +219,11 @@ * "less than" condition, each segment of equal elements will retain * the original order. The latter is slower but sometimes * prettier. Average running time: n*n/2. */ -#define list_sort( listtype, list, a, b, cond ) \ - MACRO_BEGIN \ - listtype * _newlist = NULL; \ - list_forall_unlink( a, list ) \ - list_insert_ordered( listtype, _newlist, a, b, cond ); \ - list = _newlist; \ +#define list_sort( listtype, list, a, b, cond ) \ + MACRO_BEGIN \ + listtype * _newlist = NULL; \ + list_forall_unlink( a, list ) list_insert_ordered( listtype, _newlist, a, b, cond ); \ + list = _newlist; \ MACRO_END /* a much faster sort algorithm (merge sort, n log n worst case). It @@ -213,90 +231,103 @@ * component. Note there is no curious reversal of order of equal * elements as for list_sort. */ -#define list_mergesort( listtype, list, a, b, cond ) \ - MACRO_BEGIN \ - listtype * _elt, **_hook1; \ - \ - for( _elt = list; _elt; _elt = _elt->next1 ) { \ - _elt->next1 = _elt->next; \ - _elt->next = NULL; \ - } \ - do { \ - _hook1 = &(list); \ - while( (a = *_hook1) != NULL && (b = a->next1) != NULL ) { \ - _elt = b->next1; \ - _list_merge_cond( listtype, a, b, cond, *_hook1 ); \ - _hook1 = &( (*_hook1)->next1 ); \ - *_hook1 = _elt; \ - } \ +#define list_mergesort( listtype, list, a, b, cond ) \ + MACRO_BEGIN \ + listtype * _elt, **_hook1; \ + \ + for( _elt = list; _elt; _elt = _elt->next1 ) \ + { \ + _elt->next1 = _elt->next; \ + _elt->next = NULL; \ + } \ + do \ + { \ + _hook1 = &( list ); \ + while( ( a = *_hook1 ) != NULL && ( b = a->next1 ) != NULL ) \ + { \ + _elt = b->next1; \ + _list_merge_cond( listtype, a, b, cond, *_hook1 ); \ + _hook1 = &( ( *_hook1 )->next1 ); \ + *_hook1 = _elt; \ + } \ } \ - while( _hook1 != &(list) ); \ + while( _hook1 != &( list ) ); \ MACRO_END /* merge two sorted lists. Store result at &result */ -#define _list_merge_cond( listtype, a, b, cond, result ) \ - MACRO_BEGIN \ - listtype * *_hook; \ - _hook = &(result); \ - while( 1 ) { \ - if( a==NULL ) { \ - *_hook = b; \ - break; \ - } \ - else if( b==NULL ) { \ - *_hook = a; \ - break; \ - } \ - else if( cond ) { \ - *_hook = a; \ - _hook = &(a->next); \ - a = a->next; \ - } \ - else { \ - *_hook = b; \ - _hook = &(b->next); \ - b = b->next; \ - } \ - } \ +#define _list_merge_cond( listtype, a, b, cond, result ) \ + MACRO_BEGIN \ + listtype * *_hook; \ + _hook = &( result ); \ + while( 1 ) \ + { \ + if( a == NULL ) \ + { \ + *_hook = b; \ + break; \ + } \ + else if( b == NULL ) \ + { \ + *_hook = a; \ + break; \ + } \ + else if( cond ) \ + { \ + *_hook = a; \ + _hook = &( a->next ); \ + a = a->next; \ + } \ + else \ + { \ + *_hook = b; \ + _hook = &( b->next ); \ + b = b->next; \ + } \ + } \ MACRO_END /* ---------------------------------------------------------------------- */ /* macros for doubly-linked lists */ -#define dlist_append( head, end, elt ) \ - MACRO_BEGIN \ +#define dlist_append( head, end, elt ) \ + MACRO_BEGIN \ elt->prev = end; \ elt->next = NULL; \ - if( end ) { \ - end->next = elt; \ - } \ - else { \ - head = elt; \ - } \ + if( end ) \ + { \ + end->next = elt; \ + } \ + else \ + { \ + head = elt; \ + } \ end = elt; \ MACRO_END /* let elt be each element of the list, unlinked. At the end, set list=NULL. */ -#define dlist_forall_unlink( elt, head, end ) \ - for( elt = head; \ - elt ? (head = elt->next, elt->next = NULL, elt->prev = NULL), 1 : (end = NULL, 0); \ +#define dlist_forall_unlink( elt, head, end ) \ + for( elt = head; \ + elt ? ( head = elt->next, elt->next = NULL, elt->prev = NULL ), 1 : ( end = NULL, 0 ); \ elt = head ) /* unlink the first element of the list */ -#define dlist_unlink_first( head, end, elt ) \ - MACRO_BEGIN \ - elt = head; \ - if( head ) { \ +#define dlist_unlink_first( head, end, elt ) \ + MACRO_BEGIN \ + elt = head; \ + if( head ) \ + { \ head = head->next; \ - if( head ) { \ - head->prev = NULL; \ - } \ - else { \ - end = NULL; \ - } \ + if( head ) \ + { \ + head->prev = NULL; \ + } \ + else \ + { \ + end = NULL; \ + } \ elt->prev = NULL; \ elt->next = NULL; \ - } \ + } \ MACRO_END #endif /* _PS_LISTS_H */ diff --git a/potrace/platform.h b/potrace/platform.h index d3de36359c..1b9d0af771 100644 --- a/potrace/platform.h +++ b/potrace/platform.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -8,7 +8,7 @@ #define PLATFORM_H #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif /* in Windows, set all file i/o to binary */ diff --git a/potrace/potrace_version.h b/potrace/potrace_version.h index d8193bbe55..eced7318d7 100644 --- a/potrace/potrace_version.h +++ b/potrace/potrace_version.h @@ -1 +1 @@ -#define POTRACELIB_VERSION "potracelib 1.13" +#define POTRACELIB_VERSION "potracelib 1.15" diff --git a/potrace/potracelib.cpp b/potrace/potracelib.cpp index 3cd5271b49..7f980f121e 100644 --- a/potrace/potracelib.cpp +++ b/potrace/potracelib.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -9,12 +9,11 @@ #include #include -#include "potracelib.h" #include "curve.h" #include "decompose.h" -#include "trace.h" +#include "potracelib.h" #include "progress.h" -#include +#include "trace.h" /* default parameters */ static const potrace_param_t param_default = @@ -38,14 +37,14 @@ potrace_param_t* potrace_param_default( void ) { potrace_param_t* p; - p = (potrace_param_t*) malloc( sizeof(potrace_param_t) ); + p = (potrace_param_t*) malloc( sizeof( potrace_param_t ) ); if( !p ) { return NULL; } - memcpy( p, ¶m_default, sizeof(potrace_param_t) ); + memcpy( p, ¶m_default, sizeof( potrace_param_t ) ); return p; } @@ -73,7 +72,7 @@ potrace_state_t* potrace_trace( const potrace_param_t* param, const potrace_bitm prog.d_prev = param->progress.min; /* allocate state object */ - st = (potrace_state_t*) malloc( sizeof(potrace_state_t) ); + st = (potrace_state_t*) malloc( sizeof( potrace_state_t ) ); if( !st ) { @@ -128,6 +127,7 @@ void potrace_param_free( potrace_param_t* p ) } +#include "potrace_version.h" const char* potrace_version( void ) { return POTRACELIB_VERSION; diff --git a/potrace/potracelib.h b/potrace/potracelib.h index 569c31e74e..176ed8b3b6 100644 --- a/potrace/potracelib.h +++ b/potrace/potracelib.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -27,7 +27,7 @@ extern "C" { /* structure to hold progress bar callback data */ struct potrace_progress_s { - void (* callback)( double progress, void* privdata ); /* callback fn */ + void ( * callback )( double progress, void* privdata ); /* callback fn */ void* data; /* callback function's private data */ double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */ double epsilon; /* granularity: can skip smaller increments */ @@ -58,9 +58,9 @@ typedef unsigned long potrace_word; * bit of scanline(n)[0]. */ struct potrace_bitmap_s { - int w, h; /* width and height, in pixels */ - int dy; /* words per scanline (not bytes) */ - potrace_word* map; /* raw data, dy*h words */ + int w, h; /* width and height, in pixels */ + int dy; /* words per scanline (not bytes) */ + potrace_word* map; /* raw data, dy*h words */ }; typedef struct potrace_bitmap_s potrace_bitmap_t; @@ -128,9 +128,8 @@ potrace_param_t* potrace_param_default( void ); /* free parameter set */ void potrace_param_free( potrace_param_t* p ); -/* trace a bitmap*/ -potrace_state_t* potrace_trace( const potrace_param_t* param, - const potrace_bitmap_t* bm ); +/* trace a bitmap */ +potrace_state_t* potrace_trace( const potrace_param_t* param, const potrace_bitmap_t* bm ); /* free a Potrace state */ void potrace_state_free( potrace_state_t* st ); @@ -139,7 +138,7 @@ void potrace_state_free( potrace_state_t* st ); * of potracelib */ const char* potrace_version( void ); -#ifdef __cplusplus +#ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/potrace/progress.h b/potrace/progress.h index 293e193c43..11ade84dc6 100644 --- a/potrace/progress.h +++ b/potrace/progress.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -14,12 +14,12 @@ /* structure to hold progress bar callback data */ struct progress_s { - void (* callback)( double progress, void* privdata ); /* callback fn */ + void ( * callback )( double progress, void* privdata ); /* callback fn */ void* data; /* callback function's private data */ - double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */ - double epsilon; /* granularity: can skip smaller increments */ - double b; /* upper limit of subrange in superrange units */ - double d_prev; /* previous value of d */ + double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */ + double epsilon; /* granularity: can skip smaller increments */ + double b; /* upper limit of subrange in superrange units */ + double d_prev; /* previous value of d */ }; typedef struct progress_s progress_t; @@ -32,11 +32,11 @@ static inline void progress_update( double d, progress_t* prog ) if( prog != NULL && prog->callback != NULL ) { - d_scaled = prog->min * (1 - d) + prog->max * d; + d_scaled = prog->min * ( 1 - d ) + prog->max * d; if( d == 1.0 || d_scaled >= prog->d_prev + prog->epsilon ) { - prog->callback( prog->min * (1 - d) + prog->max * d, prog->data ); + prog->callback( prog->min * ( 1 - d ) + prog->max * d, prog->data ); prog->d_prev = d_scaled; } } @@ -59,8 +59,8 @@ static inline void progress_subrange_start( double a, return; } - min = prog->min * (1 - a) + prog->max * a; - max = prog->min * (1 - b) + prog->max * b; + min = prog->min * ( 1 - a ) + prog->max * a; + max = prog->min * ( 1 - b ) + prog->max * b; if( max - min < prog->epsilon ) { @@ -71,7 +71,7 @@ static inline void progress_subrange_start( double a, sub->callback = prog->callback; sub->data = prog->data; - sub->epsilon = prog->epsilon; + sub->epsilon = prog->epsilon; sub->min = min; sub->max = max; sub->d_prev = prog->d_prev; diff --git a/potrace/render.cpp b/potrace/render.cpp index 7c550868b8..086f8043ae 100644 --- a/potrace/render.cpp +++ b/potrace/render.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -6,14 +6,14 @@ #include #endif +#include #include #include -#include #include -#include "render.h" -#include "greymap.h" #include "auxiliary.h" +#include "greymap.h" +#include "render.h" /* ---------------------------------------------------------------------- */ /* routines for anti-aliased rendering of curves */ @@ -50,16 +50,16 @@ render_t* render_new( greymap_t* gm ) { render_t* rm; - rm = (render_t*) malloc( sizeof(render_t) ); + rm = (render_t*) malloc( sizeof( render_t ) ); if( !rm ) { return NULL; } - memset( rm, 0, sizeof(render_t) ); + memset( rm, 0, sizeof( render_t ) ); rm->gm = gm; - rm->incrow_buf = (int*) calloc( gm->h, sizeof(int) ); + rm->incrow_buf = (int*) calloc( gm->h, sizeof( int ) ); if( !rm->incrow_buf ) { @@ -67,7 +67,6 @@ render_t* render_new( greymap_t* gm ) return NULL; } - memset( rm->incrow_buf, 0, gm->h * sizeof(int) ); return rm; } @@ -89,7 +88,7 @@ void render_close( render_t* rm ) render_lineto( rm, rm->x0, rm->y0 ); } - GM_INC( rm->gm, rm->x0i, rm->y0i, (rm->a0 + rm->a1) * 255 ); + GM_INC( rm->gm, rm->x0i, rm->y0i, ( rm->a0 + rm->a1 ) * 255 ); /* assert (rm->x0i != rm->x1i || rm->y0i != rm->y1i); */ @@ -144,14 +143,14 @@ static void incrow( render_t* rm, int x, int y, int b ) if( x0 < x ) { - for( i = x0; igm, i, y, -b ); } } else { - for( i = x; igm, i, y, b ); } @@ -165,8 +164,8 @@ void render_lineto( render_t* rm, double x2, double y2 ) int x2i, y2i; double t0 = 2, s0 = 2; int sn, tn; - double ss = 2, ts = 2; - double r0, r1; + double ss = 2, ts = 2; + double r0, r1; int i, j; int rxi, ryi; int s; @@ -179,27 +178,27 @@ void render_lineto( render_t* rm, double x2, double y2 ) if( sn ) { - s0 = ( (x2>rm->x1 ? rm->x1i + 1 : rm->x1i) - rm->x1 ) / (x2 - rm->x1); - ss = fabs( 1.0 / (x2 - rm->x1) ); + s0 = ( ( x2 > rm->x1 ? rm->x1i + 1 : rm->x1i ) - rm->x1 ) / ( x2 - rm->x1 ); + ss = fabs( 1.0 / ( x2 - rm->x1 ) ); } if( tn ) { - t0 = ( (y2>rm->y1 ? rm->y1i + 1 : rm->y1i) - rm->y1 ) / (y2 - rm->y1); - ts = fabs( 1.0 / (y2 - rm->y1) ); + t0 = ( ( y2 > rm->y1 ? rm->y1i + 1 : rm->y1i ) - rm->y1 ) / ( y2 - rm->y1 ); + ts = fabs( 1.0 / ( y2 - rm->y1 ) ); } r0 = 0; - i = 0; - j = 0; + i = 0; + j = 0; rxi = rm->x1i; ryi = rm->y1i; - while( i=tn || (i= tn || ( i < sn && s0 + i * ss < t0 + j * ts ) ) { r1 = s0 + i * ss; i++; @@ -215,32 +214,32 @@ void render_lineto( render_t* rm, double x2, double y2 ) /* render line from r0 to r1 segment of (rm->x1,rm->y1)..(x2,y2) */ /* move point to r1 */ - rm->a1 += (r1 - r0) * (y2 - rm->y1) * - ( rxi + 1 - ( (r0 + r1) / 2.0 * (x2 - rm->x1) + rm->x1 ) ); + rm->a1 += ( r1 - r0 ) * ( y2 - rm->y1 ) + * ( rxi + 1 - ( ( r0 + r1 ) / 2.0 * ( x2 - rm->x1 ) + rm->x1 ) ); /* move point across pixel boundary */ - if( s && x2>rm->x1 ) + if( s && x2 > rm->x1 ) { GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 ); rm->a1 = 0; rxi++; - rm->a1 += rm->y1 + r1 * (y2 - rm->y1) - ryi; + rm->a1 += rm->y1 + r1 * ( y2 - rm->y1 ) - ryi; } - else if( !s && y2>rm->y1 ) + else if( !s && y2 > rm->y1 ) { GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 ); rm->a1 = 0; incrow( rm, rxi + 1, ryi, 255 ); ryi++; } - else if( s && x2<=rm->x1 ) + else if( s && x2 <= rm->x1 ) { - rm->a1 -= rm->y1 + r1 * (y2 - rm->y1) - ryi; + rm->a1 -= rm->y1 + r1 * ( y2 - rm->y1 ) - ryi; GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 ); rm->a1 = 0; rxi--; } - else if( !s && y2<=rm->y1 ) + else if( !s && y2 <= rm->y1 ) { GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 ); rm->a1 = 0; @@ -254,8 +253,8 @@ void render_lineto( render_t* rm, double x2, double y2 ) /* move point to (x2,y2) */ r1 = 1; - rm->a1 += (r1 - r0) * (y2 - rm->y1) * - ( rxi + 1 - ( (r0 + r1) / 2.0 * (x2 - rm->x1) + rm->x1 ) ); + rm->a1 += ( r1 - r0 ) * ( y2 - rm->y1 ) + * ( rxi + 1 - ( ( r0 + r1 ) / 2.0 * ( x2 - rm->x1 ) + rm->x1 ) ); rm->x1i = x2i; rm->y1i = y2i; @@ -290,12 +289,12 @@ void render_curveto( render_t* rm, double x2, double y2, double x3, double y3, d e2 = 8 * delta <= dd ? 8 * delta / dd : 1; epsilon = sqrt( e2 ); /* necessary interval size */ - for( t = epsilon; t<1; t += epsilon ) + for( t = epsilon; t < 1; t += epsilon ) { - render_lineto( rm, x1 * cu( 1 - t ) + 3 * x2 * sq( 1 - t ) * t + 3 * x3 * (1 - t) * sq( - t ) + x4 * cu( t ), - y1 * cu( 1 - t ) + 3 * y2 * sq( 1 - t ) * t + 3 * y3 * (1 - t) * sq( t ) + y4 * - cu( t ) ); + render_lineto( rm, x1 * cu( 1 - t ) + 3 * x2 * sq( 1 - t ) * t + + 3 * x3 * ( 1 - t ) * sq( t ) + x4 * cu( t ), + y1 * cu( 1 - t ) + 3 * y2 * sq( 1 - t ) * t + 3 * y3 * ( 1 - t ) * sq( t ) + + y4 * cu( t ) ); } render_lineto( rm, x4, y4 ); diff --git a/potrace/render.h b/potrace/render.h index 1dbef69e84..0539783685 100644 --- a/potrace/render.h +++ b/potrace/render.h @@ -1,8 +1,7 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ - #ifndef RENDER_H #define RENDER_H @@ -13,8 +12,8 @@ struct render_s greymap_t* gm; double x0, y0, x1, y1; int x0i, y0i, x1i, y1i; - double a0, a1; - int* incrow_buf; + double a0, a1; + int* incrow_buf; }; typedef struct render_s render_t; diff --git a/potrace/trace.cpp b/potrace/trace.cpp index 9d0a7016a8..e1168e7e1d 100644 --- a/potrace/trace.cpp +++ b/potrace/trace.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ @@ -8,25 +8,26 @@ #include #endif -#include #include +#include #include #include -#include "potracelib.h" +#include "auxiliary.h" #include "curve.h" #include "lists.h" -#include "auxiliary.h" -#include "trace.h" +#include "potracelib.h" #include "progress.h" +#include "trace.h" -#define INFTY 10000000 /* it suffices that this is longer than any +#define INFTY \ + 10000000 /* it suffices that this is longer than any * path; it need not be really infinite */ -#define COS179 -0.999847695156 /* the cosine of 179 degrees */ +#define COS179 -0.999847695156 /* the cosine of 179 degrees */ /* ---------------------------------------------------------------------- */ -#define SAFE_CALLOC( var, n, typ ) \ - if( ( var = (typ*) calloc( n, sizeof(typ) ) ) == NULL ) \ +#define SAFE_CALLOC( var, n, typ ) \ + if( ( var = (typ*) calloc( n, sizeof( typ ) ) ) == NULL ) \ goto calloc_error /* ---------------------------------------------------------------------- */ @@ -65,20 +66,20 @@ static inline double ddenom( dpoint_t p0, dpoint_t p2 ) { point_t r = dorth_infty( p0, p2 ); - return r.y * (p2.x - p0.x) - r.x * (p2.y - p0.y); + return r.y * ( p2.x - p0.x ) - r.x * ( p2.y - p0.y ); } /* return 1 if a <= b < c < a, in a cyclic sense (mod n) */ static inline int cyclic( int a, int b, int c ) { - if( a<=c ) + if( a <= c ) { - return a<=b && blen; sums_t* sums = pp->sums; - double x, y, x2, xy, y2; - double k; - double a, b, c, lambda2, l; + double x, y, x2, xy, y2; + double k; + double a, b, c, lambda2, l; int r = 0; /* rotations from i to j */ - while( j>=n ) + while( j >= n ) { - j -= n; - r += 1; + j -= n; + r += 1; } - while( i>=n ) + while( i >= n ) { - i -= n; - r -= 1; + i -= n; + r -= 1; } - while( j<0 ) + while( j < 0 ) { - j += n; - r -= 1; + j += n; + r -= 1; } - while( i<0 ) + while( i < 0 ) { - i += n; - r += 1; + i += n; + r += 1; } - x = sums[j + 1].x - sums[i].x + r * sums[n].x; - y = sums[j + 1].y - sums[i].y + r * sums[n].y; + x = sums[j + 1].x - sums[i].x + r * sums[n].x; + y = sums[j + 1].y - sums[i].y + r * sums[n].y; x2 = sums[j + 1].x2 - sums[i].x2 + r * sums[n].x2; xy = sums[j + 1].xy - sums[i].xy + r * sums[n].xy; y2 = sums[j + 1].y2 - sums[i].y2 + r * sums[n].y2; @@ -131,21 +132,21 @@ static void pointslope( privpath_t* pp, int i, int j, dpoint_t* ctr, dpoint_t* d ctr->x = x / k; ctr->y = y / k; - a = (x2 - (double) x * x / k) / k; - b = (xy - (double) x * y / k) / k; - c = (y2 - (double) y * y / k) / k; + a = ( x2 - (double) x * x / k ) / k; + b = ( xy - (double) x * y / k ) / k; + c = ( y2 - (double) y * y / k ) / k; - lambda2 = ( a + c + sqrt( (a - c) * (a - c) + 4 * b * b ) ) / 2; /* larger e.value */ + lambda2 = ( a + c + sqrt( ( a - c ) * ( a - c ) + 4 * b * b ) ) / 2; /* larger e.value */ /* now find e.vector for lambda2 */ - a -= lambda2; - c -= lambda2; + a -= lambda2; + c -= lambda2; if( fabs( a ) >= fabs( c ) ) { l = sqrt( a * a + b * b ); - if( l!=0 ) + if( l != 0 ) { dir->x = -b / l; dir->y = a / l; @@ -155,14 +156,14 @@ static void pointslope( privpath_t* pp, int i, int j, dpoint_t* ctr, dpoint_t* d { l = sqrt( c * c + b * b ); - if( l!=0 ) + if( l != 0 ) { dir->x = -c / l; dir->y = b / l; } } - if( l==0 ) + if( l == 0 ) { dir->x = dir->y = 0; /* sometimes this can happen when k=4: * the two eigenvalues coincide */ @@ -182,14 +183,14 @@ static inline double quadform( quadform_t Q, dpoint_t w ) int i, j; double sum; - v[0] = w.x; - v[1] = w.y; - v[2] = 1; - sum = 0.0; + v[0] = w.x; + v[1] = w.y; + v[2] = 1; + sum = 0.0; - for( i = 0; i<3; i++ ) + for( i = 0; i < 3; i++ ) { - for( j = 0; j<3; j++ ) + for( j = 0; j < 3; j++ ) { sum += v[i] * Q[i][j] * v[j]; } @@ -265,8 +266,10 @@ static inline dpoint_t bezier( double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, * following to 16 multiplications, using common subexpression * elimination. */ - res.x = s * s * s * p0.x + 3 * (s * s * t) * p1.x + 3 * (t * t * s) * p2.x + t * t * t * p3.x; - res.y = s * s * s * p0.y + 3 * (s * s * t) * p1.y + 3 * (t * t * s) * p2.y + t * t * t * p3.y; + res.x = s * s * s * p0.x + 3 * ( s * s * t ) * p1.x + 3 * ( t * t * s ) * p2.x + + t * t * t * p3.x; + res.y = s * s * s * p0.y + 3 * ( s * s * t ) * p1.y + 3 * ( t * t * s ) * p2.y + + t * t * t * p3.y; return res; } @@ -278,29 +281,29 @@ static inline dpoint_t bezier( double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, static double tangent( dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3, dpoint_t q0, dpoint_t q1 ) { - double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */ - double a, b, c; /* a t^2 + b t + c = 0 */ - double d, s, r1, r2; + double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */ + double a, b, c; /* a t^2 + b t + c = 0 */ + double d, s, r1, r2; - A = cprod( p0, p1, q0, q1 ); - B = cprod( p1, p2, q0, q1 ); - C = cprod( p2, p3, q0, q1 ); + A = cprod( p0, p1, q0, q1 ); + B = cprod( p1, p2, q0, q1 ); + C = cprod( p2, p3, q0, q1 ); - a = A - 2 * B + C; - b = -2 * A + 2 * B; - c = A; + a = A - 2 * B + C; + b = -2 * A + 2 * B; + c = A; d = b * b - 4 * a * c; - if( a==0 || d<0 ) + if( a == 0 || d < 0 ) { return -1.0; } s = sqrt( d ); - r1 = (-b + s) / (2 * a); - r2 = (-b - s) / (2 * a); + r1 = ( -b + s ) / ( 2 * a ); + r2 = ( -b - s ) / ( 2 * a ); if( r1 >= 0 && r1 <= 1 ) { @@ -335,15 +338,15 @@ static int calc_sums( privpath_t* pp ) /* preparatory computation for later fast summing */ pp->sums[0].x2 = pp->sums[0].xy = pp->sums[0].y2 = pp->sums[0].x = pp->sums[0].y = 0; - for( i = 0; ipt[i].x - pp->x0; - y = pp->pt[i].y - pp->y0; - pp->sums[i + 1].x = pp->sums[i].x + x; - pp->sums[i + 1].y = pp->sums[i].y + y; - pp->sums[i + 1].x2 = pp->sums[i].x2 + x * x; - pp->sums[i + 1].xy = pp->sums[i].xy + x * y; - pp->sums[i + 1].y2 = pp->sums[i].y2 + y * y; + x = pp->pt[i].x - pp->x0; + y = pp->pt[i].y - pp->y0; + pp->sums[i + 1].x = pp->sums[i].x + x; + pp->sums[i + 1].y = pp->sums[i].y + y; + pp->sums[i + 1].x2 = pp->sums[i].x2 + (double) x * x; + pp->sums[i + 1].xy = pp->sums[i].xy + (double) x * y; + pp->sums[i + 1].y2 = pp->sums[i].y2 + (double) y * y; } return 0; @@ -409,7 +412,7 @@ static int calc_lon( privpath_t* pp ) * above. */ k = 0; - for( i = n - 1; i>=0; i-- ) + for( i = n - 1; i >= 0; i-- ) { if( pt[i].x != pt[k].x && pt[i].y != pt[k].y ) { @@ -424,12 +427,13 @@ static int calc_lon( privpath_t* pp ) /* determine pivot points: for each i, let pivk[i] be the furthest k * such that all j with i=0; i-- ) + for( i = n - 1; i >= 0; i-- ) { ct[0] = ct[1] = ct[2] = ct[3] = 0; /* keep track of "directions" that have occurred */ - dir = ( 3 + 3 * (pt[mod( i + 1, n )].x - pt[i].x) + (pt[mod( i + 1, n )].y - pt[i].y) ) / 2; + dir = ( 3 + 3 * ( pt[mod( i + 1, n )].x - pt[i].x ) + ( pt[mod( i + 1, n )].y - pt[i].y ) ) + / 2; ct[dir]++; constraint[0].x = 0; @@ -438,8 +442,8 @@ static int calc_lon( privpath_t* pp ) constraint[1].y = 0; /* find the next k such that no straight line from i to k */ - k = nc[i]; - k1 = i; + k = nc[i]; + k1 = i; while( 1 ) { @@ -453,8 +457,8 @@ static int calc_lon( privpath_t* pp ) goto foundk; } - cur.x = pt[k].x - pt[i].x; - cur.y = pt[k].y - pt[i].y; + cur.x = pt[k].x - pt[i].x; + cur.y = pt[k].y - pt[i].y; /* see if current constraint is violated */ if( xprod( constraint[0], cur ) < 0 || xprod( constraint[1], cur ) > 0 ) @@ -469,16 +473,16 @@ static int calc_lon( privpath_t* pp ) } else { - off.x = cur.x + ( ( cur.y>=0 && (cur.y>0 || cur.x<0) ) ? 1 : -1 ); - off.y = cur.y + ( ( cur.x<=0 && (cur.x<0 || cur.y<0) ) ? 1 : -1 ); + off.x = cur.x + ( ( cur.y >= 0 && ( cur.y > 0 || cur.x < 0 ) ) ? 1 : -1 ); + off.y = cur.y + ( ( cur.x <= 0 && ( cur.x < 0 || cur.y < 0 ) ) ? 1 : -1 ); if( xprod( constraint[0], off ) >= 0 ) { constraint[0] = off; } - off.x = cur.x + ( ( cur.y<=0 && (cur.y<0 || cur.x<0) ) ? 1 : -1 ); - off.y = cur.y + ( ( cur.x>=0 && (cur.x>0 || cur.y<0) ) ? 1 : -1 ); + off.x = cur.x + ( ( cur.y <= 0 && ( cur.y < 0 || cur.x < 0 ) ) ? 1 : -1 ); + off.y = cur.y + ( ( cur.x >= 0 && ( cur.x > 0 || cur.y < 0 ) ) ? 1 : -1 ); if( xprod( constraint[1], off ) <= 0 ) { @@ -499,34 +503,33 @@ constraint_viol: /* k1 was the last "corner" satisfying the current constraint, and * k is the first one violating it. We now need to find the last * point along k1..k which satisfied the constraint. */ - dk.x = sign( pt[k].x - pt[k1].x ); - dk.y = sign( pt[k].y - pt[k1].y ); - cur.x = pt[k1].x - pt[i].x; - cur.y = pt[k1].y - pt[i].y; + dk.x = sign( pt[k].x - pt[k1].x ); + dk.y = sign( pt[k].y - pt[k1].y ); + cur.x = pt[k1].x - pt[i].x; + cur.y = pt[k1].y - pt[i].y; /* find largest integer j such that xprod(constraint[0], cur+j*dk) * >= 0 and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity * of xprod. */ - a = xprod( constraint[0], cur ); - b = xprod( constraint[0], dk ); - c = xprod( constraint[1], cur ); - d = xprod( constraint[1], dk ); + a = xprod( constraint[0], cur ); + b = xprod( constraint[0], dk ); + c = xprod( constraint[1], cur ); + d = xprod( constraint[1], dk ); /* find largest integer j such that a+j*b>=0 and c+j*d<=0. This * can be solved with integer arithmetic. */ j = INFTY; - if( b<0 ) + if( b < 0 ) { j = floordiv( a, -b ); } - if( d>0 ) + if( d > 0 ) { j = min( j, floordiv( -c, d ) ); } pivk[i] = mod( k1 + j, n ); -foundk: - ; +foundk:; } /* for i */ /* clean up: for each i, let lon[i] be the largest k such that for @@ -535,7 +538,7 @@ foundk: j = pivk[n - 1]; pp->lon[n - 1] = j; - for( i = n - 2; i>=0; i-- ) + for( i = n - 2; i >= 0; i-- ) { if( cyclic( i + 1, pivk[i], j ) ) { @@ -570,28 +573,28 @@ calloc_error: static double penalty3( privpath_t* pp, int i, int j ) { int n = pp->len; - point_t* pt = pp->pt; - sums_t* sums = pp->sums; + point_t* pt = pp->pt; + sums_t* sums = pp->sums; /* assume 0<=i=n ) + if( j >= n ) { - j -= n; - r = 1; + j -= n; + r = 1; } /* critical inner loop: the "if" gives a 4.6 percent speedup */ if( r == 0 ) { - x = sums[j + 1].x - sums[i].x; - y = sums[j + 1].y - sums[i].y; + x = sums[j + 1].x - sums[i].x; + y = sums[j + 1].y - sums[i].y; x2 = sums[j + 1].x2 - sums[i].x2; xy = sums[j + 1].xy - sums[i].xy; y2 = sums[j + 1].y2 - sums[i].y2; @@ -599,22 +602,22 @@ static double penalty3( privpath_t* pp, int i, int j ) } else { - x = sums[j + 1].x - sums[i].x + sums[n].x; - y = sums[j + 1].y - sums[i].y + sums[n].y; + x = sums[j + 1].x - sums[i].x + sums[n].x; + y = sums[j + 1].y - sums[i].y + sums[n].y; x2 = sums[j + 1].x2 - sums[i].x2 + sums[n].x2; xy = sums[j + 1].xy - sums[i].xy + sums[n].xy; y2 = sums[j + 1].y2 - sums[i].y2 + sums[n].y2; k = j + 1 - i + n; } - px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x; - py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y; - ey = (pt[j].x - pt[i].x); - ex = -(pt[j].y - pt[i].y); + px = ( pt[i].x + pt[j].x ) / 2.0 - pt[0].x; + py = ( pt[i].y + pt[j].y ) / 2.0 - pt[0].y; + ey = ( pt[j].x - pt[i].x ); + ex = -( pt[j].y - pt[i].y ); - a = ( (x2 - 2 * x * px) / k + px * px ); - b = ( (xy - x * py - y * px) / k + px * py ); - c = ( (y2 - 2 * y * py) / k + py * py ); + a = ( ( x2 - 2 * x * px ) / k + px * px ); + b = ( ( xy - x * py - y * px ) / k + px * py ); + c = ( ( y2 - 2 * y * py ) / k + py * py ); s = ex * ex * a + 2 * ex * ey * b + ey * ey * c; @@ -629,12 +632,12 @@ static int bestpolygon( privpath_t* pp ) { int i, j, m, k; int n = pp->len; - double* pen = NULL; /* pen[n+1]: penalty vector */ - int* prev = NULL; /* prev[n+1]: best path pointer vector */ - int* clip0 = NULL; /* clip0[n]: longest segment pointer, non-cyclic */ - int* clip1 = NULL; /* clip1[n+1]: backwards segment pointer, non-cyclic */ - int* seg0 = NULL; /* seg0[m+1]: forward segment bounds, m<=n */ - int* seg1 = NULL; /* seg1[m+1]: backward segment bounds, m<=n */ + double* pen = NULL; /* pen[n+1]: penalty vector */ + int* prev = NULL; /* prev[n+1]: best path pointer vector */ + int* clip0 = NULL; /* clip0[n]: longest segment pointer, non-cyclic */ + int* clip1 = NULL; /* clip1[n+1]: backwards segment pointer, non-cyclic */ + int* seg0 = NULL; /* seg0[m+1]: forward segment bounds, m<=n */ + int* seg1 = NULL; /* seg1[m+1]: backward segment bounds, m<=n */ double thispen; double best; int c; @@ -647,7 +650,7 @@ static int bestpolygon( privpath_t* pp ) SAFE_CALLOC( seg1, n + 1, int ); /* calculate clipped paths */ - for( i = 0; ilon[mod( i - 1, n )] - 1, n ); @@ -670,7 +673,7 @@ static int bestpolygon( privpath_t* pp ) * clip1[j] <= i, for i,j=0..n. */ j = 1; - for( i = 0; i0; j-- ) + for( j = m; j > 0; j-- ) { seg1[j] = i; i = clip1[i]; @@ -708,13 +711,13 @@ static int bestpolygon( privpath_t* pp ) * close to linear since the inner loop tends to be short. */ pen[0] = 0; - for( j = 1; j<=m; j++ ) + for( j = 1; j <= m; j++ ) { - for( i = seg1[j]; i<=seg0[j]; i++ ) + for( i = seg1[j]; i <= seg0[j]; i++ ) { best = -1; - for( k = seg0[j - 1]; k>=clip1[i]; k-- ) + for( k = seg0[j - 1]; k >= clip1[i]; k-- ) { thispen = penalty3( pp, k, i ) + pen[k]; @@ -733,7 +736,7 @@ static int bestpolygon( privpath_t* pp ) SAFE_CALLOC( pp->po, m, int ); /* read off shortest path */ - for( i = n, j = m - 1; i>0; j-- ) + for( i = n, j = m - 1; i > 0; j-- ) { i = prev[i]; pp->po[j] = i; @@ -769,17 +772,17 @@ calloc_error: static int adjust_vertices( privpath_t* pp ) { int m = pp->m; - int* po = pp->po; - int n = pp->len; + int* po = pp->po; + int n = pp->len; point_t* pt = pp->pt; int x0 = pp->x0; int y0 = pp->y0; - dpoint_t* ctr = NULL; /* ctr[m] */ - dpoint_t* dir = NULL; /* dir[m] */ - quadform_t* q = NULL; /* q[m] */ - double v[3]; - double d; + dpoint_t* ctr = NULL; /* ctr[m] */ + dpoint_t* dir = NULL; /* dir[m] */ + quadform_t* q = NULL; /* q[m] */ + double v[3]; + double d; int i, j, k, l; dpoint_t s; int r; @@ -797,25 +800,25 @@ static int adjust_vertices( privpath_t* pp ) /* calculate "optimal" point-slope representation for each line * segment */ - for( i = 0; iQ[1][1] ) + if( Q[0][0] > Q[1][1] ) { - v[0] = -Q[0][1]; - v[1] = Q[0][0]; + v[0] = -Q[0][1]; + v[1] = Q[0][0]; } else if( Q[1][1] ) { - v[0] = -Q[1][1]; - v[1] = Q[1][0]; + v[0] = -Q[1][1]; + v[1] = Q[1][0]; } else { - v[0] = 1; - v[1] = 0; + v[0] = 1; + v[1] = 0; } d = sq( v[0] ) + sq( v[1] ); v[2] = -v[1] * s.y - v[0] * s.x; - for( l = 0; l<3; l++ ) + for( l = 0; l < 3; l++ ) { - for( k = 0; k<3; k++ ) + for( k = 0; k < 3; k++ ) { Q[l][k] += v[l] * v[k] / d; } @@ -922,34 +925,35 @@ static int adjust_vertices( privpath_t* pp ) if( dx <= .5 && dy <= .5 ) { - pp->curve.vertex[i].x = w.x + x0; - pp->curve.vertex[i].y = w.y + y0; + pp->curve.vertex[i].x = w.x + x0; + pp->curve.vertex[i].y = w.y + y0; continue; } /* the minimum was not in the unit square; now minimize quadratic * on boundary of square */ - min = quadform( Q, s ); - xmin = s.x; - ymin = s.y; + min = quadform( Q, s ); + xmin = s.x; + ymin = s.y; if( Q[0][0] == 0.0 ) { goto fixx; } - for( z = 0; z<2; z++ ) /* value of the y-coordinate */ + for( z = 0; z < 2; z++ ) { - w.y = s.y - 0.5 + z; - w.x = -(Q[0][1] * w.y + Q[0][2]) / Q[0][0]; - dx = fabs( w.x - s.x ); - cand = quadform( Q, w ); + /* value of the y-coordinate */ + w.y = s.y - 0.5 + z; + w.x = -( Q[0][1] * w.y + Q[0][2] ) / Q[0][0]; + dx = fabs( w.x - s.x ); + cand = quadform( Q, w ); if( dx <= .5 && cand < min ) { - min = cand; - xmin = w.x; - ymin = w.y; + min = cand; + xmin = w.x; + ymin = w.y; } } @@ -960,43 +964,44 @@ fixx: goto corners; } - for( z = 0; z<2; z++ ) /* value of the x-coordinate */ + for( z = 0; z < 2; z++ ) { - w.x = s.x - 0.5 + z; - w.y = -(Q[1][0] * w.x + Q[1][2]) / Q[1][1]; - dy = fabs( w.y - s.y ); - cand = quadform( Q, w ); + /* value of the x-coordinate */ + w.x = s.x - 0.5 + z; + w.y = -( Q[1][0] * w.x + Q[1][2] ) / Q[1][1]; + dy = fabs( w.y - s.y ); + cand = quadform( Q, w ); if( dy <= .5 && cand < min ) { - min = cand; - xmin = w.x; - ymin = w.y; + min = cand; + xmin = w.x; + ymin = w.y; } } corners: /* check four corners */ - for( l = 0; l<2; l++ ) + for( l = 0; l < 2; l++ ) { - for( k = 0; k<2; k++ ) + for( k = 0; k < 2; k++ ) { - w.x = s.x - 0.5 + l; - w.y = s.y - 0.5 + k; - cand = quadform( Q, w ); + w.x = s.x - 0.5 + l; + w.y = s.y - 0.5 + k; + cand = quadform( Q, w ); if( cand < min ) { - min = cand; - xmin = w.x; - ymin = w.y; + min = cand; + xmin = w.x; + ymin = w.y; } } } - pp->curve.vertex[i].x = xmin + x0; - pp->curve.vertex[i].y = ymin + y0; + pp->curve.vertex[i].x = xmin + x0; + pp->curve.vertex[i].y = ymin + y0; continue; } @@ -1023,11 +1028,11 @@ static void reverse( privcurve_t* curve ) int i, j; dpoint_t tmp; - for( i = 0, j = m - 1; ivertex[i]; - curve->vertex[i] = curve->vertex[j]; - curve->vertex[j] = tmp; + curve->vertex[i] = curve->vertex[j]; + curve->vertex[j] = tmp; } } @@ -1042,11 +1047,11 @@ static void smooth( privcurve_t* curve, double alphamax ) dpoint_t p2, p3, p4; /* examine each vertex and find its best fit */ - for( i = 0; ivertex[k], curve->vertex[j] ); + j = mod( i + 1, m ); + k = mod( i + 2, m ); + p4 = interval( 1 / 2.0, curve->vertex[k], curve->vertex[j] ); denom = ddenom( curve->vertex[i], curve->vertex[k] ); @@ -1054,19 +1059,20 @@ static void smooth( privcurve_t* curve, double alphamax ) { dd = dpara( curve->vertex[i], curve->vertex[j], curve->vertex[k] ) / denom; dd = fabs( dd ); - alpha = dd>1 ? (1 - 1.0 / dd) : 0; - alpha = alpha / 0.75; + alpha = dd > 1 ? ( 1 - 1.0 / dd ) : 0; + alpha = alpha / 0.75; } else { alpha = 4 / 3.0; } - curve->alpha0[j] = alpha; /* remember "original" value of alpha */ + curve->alpha0[j] = alpha; /* remember "original" value of alpha */ - if( alpha >= alphamax ) /* pointed corner */ + if( alpha >= alphamax ) { - curve->tag[j] = POTRACE_CORNER; + /* pointed corner */ + curve->tag[j] = POTRACE_CORNER; curve->c[j][1] = curve->vertex[j]; curve->c[j][2] = p4; } @@ -1083,7 +1089,7 @@ static void smooth( privcurve_t* curve, double alphamax ) p2 = interval( .5 + .5 * alpha, curve->vertex[i], curve->vertex[j] ); p3 = interval( .5 + .5 * alpha, curve->vertex[k], curve->vertex[j] ); - curve->tag[j] = POTRACE_CURVETO; + curve->tag[j] = POTRACE_CURVETO; curve->c[j][0] = p2; curve->c[j][1] = p3; curve->c[j][2] = p4; @@ -1103,10 +1109,10 @@ static void smooth( privcurve_t* curve, double alphamax ) /* a private type for the result of opti_penalty */ struct opti_s { - double pen; /* penalty */ - dpoint_t c[2]; /* curve parameters */ - double t, s; /* curve parameters */ - double alpha; /* curve parameter */ + double pen; /* penalty */ + dpoint_t c[2]; /* curve parameters */ + double t, s; /* curve parameters */ + double alpha; /* curve parameter */ }; typedef struct opti_s opti_t; @@ -1124,18 +1130,19 @@ static int opti_penalty( privpath_t* pp, int m = pp->curve.n; int k, k1, k2, conv, i1; double area, alpha, d, d1, d2; - dpoint_t p0, p1, p2, p3, pt; - double A, R, A1, A2, A3, A4; - double s, t; + dpoint_t p0, p1, p2, p3, pt; + double A, R, A1, A2, A3, A4; + double s, t; /* check convexity, corner-freeness, and maximum bend < 179 degrees */ - if( i==j ) /* sanity - a full loop can never be an opticurve */ + if( i == j ) { + /* sanity - a full loop can never be an opticurve */ return 1; } - k = i; + k = i; i1 = mod( i + 1, m ); k1 = mod( k + 1, m ); conv = convc[k1]; @@ -1147,7 +1154,7 @@ static int opti_penalty( privpath_t* pp, d = ddist( pp->curve.vertex[i], pp->curve.vertex[i1] ); - for( k = k1; k!=j; k = k1 ) + for( k = k1; k != j; k = k1 ) { k1 = mod( k + 1, m ); k2 = mod( k + 2, m ); @@ -1158,14 +1165,15 @@ static int opti_penalty( privpath_t* pp, } if( sign( cprod( pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], - pp->curve.vertex[k2] ) ) != conv ) + pp->curve.vertex[k2] ) ) + != conv ) { return 1; } if( iprod1( pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], - pp->curve.vertex[k2] ) < - d * ddist( pp->curve.vertex[k1], pp->curve.vertex[k2] ) * COS179 ) + pp->curve.vertex[k2] ) + < d * ddist( pp->curve.vertex[k1], pp->curve.vertex[k2] ) * COS179 ) { return 1; } @@ -1178,10 +1186,10 @@ static int opti_penalty( privpath_t* pp, p3 = pp->curve.c[mod( j, m )][2]; /* determine its area */ - area = areac[j] - areac[i]; - area -= dpara( pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2] ) / 2; + area = areac[j] - areac[i]; + area -= dpara( pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2] ) / 2; - if( i>=j ) + if( i >= j ) { area += areac[m]; } @@ -1196,26 +1204,28 @@ static int opti_penalty( privpath_t* pp, /* A4 = dpara(p1, p2, p3); */ A4 = A1 + A3 - A2; - if( A2 == A1 ) /* this should never happen */ + if( A2 == A1 ) { + /* this should never happen */ return 1; } - t = A3 / (A3 - A4); - s = A2 / (A2 - A1); - A = A2 * t / 2.0; + t = A3 / ( A3 - A4 ); + s = A2 / ( A2 - A1 ); + A = A2 * t / 2.0; - if( A == 0.0 ) /* this should never happen */ + if( A == 0.0 ) { + /* this should never happen */ return 1; } R = area / A; /* relative area */ alpha = 2 - sqrt( 4 - R / 0.3 ); /* overall alpha for p0-o-p3 curve */ - res->c[0] = interval( t * alpha, p0, p1 ); - res->c[1] = interval( s * alpha, p3, p2 ); - res->alpha = alpha; + res->c[0] = interval( t * alpha, p0, p1 ); + res->c[1] = interval( s * alpha, p3, p2 ); + res->alpha = alpha; res->t = t; res->s = s; @@ -1226,12 +1236,12 @@ static int opti_penalty( privpath_t* pp, /* calculate penalty */ /* check tangency with edges */ - for( k = mod( i + 1, m ); k!=j; k = k1 ) + for( k = mod( i + 1, m ); k != j; k = k1 ) { k1 = mod( k + 1, m ); t = tangent( p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1] ); - if( t<-.5 ) + if( t < -.5 ) { return 1; } @@ -1239,8 +1249,9 @@ static int opti_penalty( privpath_t* pp, pt = bezier( t, p0, p1, p2, p3 ); d = ddist( pp->curve.vertex[k], pp->curve.vertex[k1] ); - if( d == 0.0 ) /* this should never happen */ + if( d == 0.0 ) { + /* this should never happen */ return 1; } @@ -1251,8 +1262,8 @@ static int opti_penalty( privpath_t* pp, return 1; } - if( iprod( pp->curve.vertex[k], pp->curve.vertex[k1], - pt ) < 0 || iprod( pp->curve.vertex[k1], pp->curve.vertex[k], pt ) < 0 ) + if( iprod( pp->curve.vertex[k], pp->curve.vertex[k1], pt ) < 0 + || iprod( pp->curve.vertex[k1], pp->curve.vertex[k], pt ) < 0 ) { return 1; } @@ -1261,12 +1272,12 @@ static int opti_penalty( privpath_t* pp, } /* check corners */ - for( k = i; k!=j; k = k1 ) + for( k = i; k != j; k = k1 ) { k1 = mod( k + 1, m ); t = tangent( p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2] ); - if( t<-.5 ) + if( t < -.5 ) { return 1; } @@ -1274,8 +1285,9 @@ static int opti_penalty( privpath_t* pp, pt = bezier( t, p0, p1, p2, p3 ); d = ddist( pp->curve.c[k][2], pp->curve.c[k1][2] ); - if( d == 0.0 ) /* this should never happen */ + if( d == 0.0 ) { + /* this should never happen */ return 1; } @@ -1319,10 +1331,10 @@ static int opticurve( privpath_t* pp, double opttolerance ) opti_t o; dpoint_t p0; int i1; - double area; - double alpha; - double* s = NULL; - double* t = NULL; + double area; + double alpha; + double* s = NULL; + double* t = NULL; int* convc = NULL; /* conv[m]: pre-computed convexities */ double* areac = NULL; /* cumarea[m+1]: cache for fast area computation */ @@ -1335,13 +1347,12 @@ static int opticurve( privpath_t* pp, double opttolerance ) SAFE_CALLOC( areac, m + 1, double ); /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */ - for( i = 0; icurve.tag[i] == POTRACE_CURVETO ) { - convc[i] = - sign( dpara( pp->curve.vertex[mod( i - 1, m )], pp->curve.vertex[i], - pp->curve.vertex[mod( i + 1, m )] ) ); + convc[i] = sign( dpara( pp->curve.vertex[mod( i - 1, m )], pp->curve.vertex[i], + pp->curve.vertex[mod( i + 1, m )] ) ); } else { @@ -1354,37 +1365,36 @@ static int opticurve( privpath_t* pp, double opttolerance ) areac[0] = 0.0; p0 = pp->curve.vertex[0]; - for( i = 0; icurve.tag[i1] == POTRACE_CURVETO ) { - alpha = pp->curve.alpha[i1]; - area += 0.3 * alpha * (4 - alpha) * dpara( pp->curve.c[i][2], - pp->curve.vertex[i1], - pp->curve.c[i1][2] ) / 2; + alpha = pp->curve.alpha[i1]; + area += 0.3 * alpha * ( 4 - alpha ) + * dpara( pp->curve.c[i][2], pp->curve.vertex[i1], pp->curve.c[i1][2] ) / 2; area += dpara( p0, pp->curve.c[i][2], pp->curve.c[i1][2] ) / 2; } areac[i + 1] = area; } - pt[0] = -1; + pt[0] = -1; pen[0] = 0; len[0] = 0; /* Fixme: we always start from a fixed point -- should find the best * curve cyclically */ - for( j = 1; j<=m; j++ ) + for( j = 1; j <= m; j++ ) { /* calculate best path from 0 to j */ - pt[j] = j - 1; + pt[j] = j - 1; pen[j] = pen[j - 1]; len[j] = len[j - 1] + 1; - for( i = j - 2; i>=0; i-- ) + for( i = j - 2; i >= 0; i-- ) { r = opti_penalty( pp, i, mod( j, m ), &o, opttolerance, convc, areac ); @@ -1393,9 +1403,9 @@ static int opticurve( privpath_t* pp, double opttolerance ) break; } - if( len[j] > len[i] + 1 || (len[j] == len[i] + 1 && pen[j] > pen[i] + o.pen) ) + if( len[j] > len[i] + 1 || ( len[j] == len[i] + 1 && pen[j] > pen[i] + o.pen ) ) { - pt[j] = i; + pt[j] = i; pen[j] = pen[i] + o.pen; len[j] = len[i] + 1; opt[j] = o; @@ -1416,43 +1426,42 @@ static int opticurve( privpath_t* pp, double opttolerance ) j = m; - for( i = om - 1; i>=0; i-- ) + for( i = om - 1; i >= 0; i-- ) { - if( pt[j]==j - 1 ) + if( pt[j] == j - 1 ) { - pp->ocurve.tag[i] = pp->curve.tag[mod( j, m )]; + pp->ocurve.tag[i] = pp->curve.tag[mod( j, m )]; pp->ocurve.c[i][0] = pp->curve.c[mod( j, m )][0]; pp->ocurve.c[i][1] = pp->curve.c[mod( j, m )][1]; pp->ocurve.c[i][2] = pp->curve.c[mod( j, m )][2]; - pp->ocurve.vertex[i] = pp->curve.vertex[mod( j, m )]; - pp->ocurve.alpha[i] = pp->curve.alpha[mod( j, m )]; - pp->ocurve.alpha0[i] = pp->curve.alpha0[mod( j, m )]; + pp->ocurve.vertex[i] = pp->curve.vertex[mod( j, m )]; + pp->ocurve.alpha[i] = pp->curve.alpha[mod( j, m )]; + pp->ocurve.alpha0[i] = pp->curve.alpha0[mod( j, m )]; pp->ocurve.beta[i] = pp->curve.beta[mod( j, m )]; s[i] = t[i] = 1.0; } else { - pp->ocurve.tag[i] = POTRACE_CURVETO; + pp->ocurve.tag[i] = POTRACE_CURVETO; pp->ocurve.c[i][0] = opt[j].c[0]; pp->ocurve.c[i][1] = opt[j].c[1]; pp->ocurve.c[i][2] = pp->curve.c[mod( j, m )][2]; - pp->ocurve.vertex[i] = interval( opt[j].s, pp->curve.c[mod( j, - m )][2], - pp->curve.vertex[mod( j, m )] ); - pp->ocurve.alpha[i] = opt[j].alpha; - pp->ocurve.alpha0[i] = opt[j].alpha; - s[i] = opt[j].s; - t[i] = opt[j].t; + pp->ocurve.vertex[i] = interval( + opt[j].s, pp->curve.c[mod( j, m )][2], pp->curve.vertex[mod( j, m )] ); + pp->ocurve.alpha[i] = opt[j].alpha; + pp->ocurve.alpha0[i] = opt[j].alpha; + s[i] = opt[j].s; + t[i] = opt[j].t; } j = pt[j]; } /* calculate beta parameters */ - for( i = 0; iocurve.beta[i] = s[i] / (s[i] + t[i1]); + pp->ocurve.beta[i] = s[i] / ( s[i] + t[i1] ); } pp->ocurve.alphacurve = 1; @@ -1482,7 +1491,8 @@ calloc_error: /* ---------------------------------------------------------------------- */ -#define TRY( x ) if( x ) \ +#define TRY( x ) \ + if( x ) \ goto try_error /* return 0 on success, 1 on error with errno set. */ @@ -1508,8 +1518,9 @@ int process_path( path_t* plist, const potrace_param_t* param, progress_t* progr TRY( bestpolygon( p->priv ) ); TRY( adjust_vertices( p->priv ) ); - if( p->sign == '-' ) /* reverse orientation of negative paths */ + if( p->sign == '-' ) { + /* reverse orientation of negative paths */ reverse( &p->priv->curve ); } diff --git a/potrace/trace.h b/potrace/trace.h index 940f2ae888..e25f0ba97f 100644 --- a/potrace/trace.h +++ b/potrace/trace.h @@ -1,14 +1,13 @@ -/* Copyright (C) 2001-2015 Peter Selinger. +/* Copyright (C) 2001-2017 Peter Selinger. * This file is part of Potrace. It is free software and it is covered * by the GNU General Public License. See the file COPYING for details. */ - #ifndef TRACE_H #define TRACE_H +#include "curve.h" #include "potracelib.h" #include "progress.h" -#include "curve.h" int process_path( path_t* plist, const potrace_param_t* param, progress_t* progress );