Update potrace to version 1.15 (that fixes some bugs)

This commit is contained in:
jean-pierre charras 2017-11-27 12:54:18 +01:00
parent e5847b7953
commit 23d1905c55
21 changed files with 1390 additions and 953 deletions

View File

@ -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 * 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. */ * 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; dpoint_t res;
res.x = a.x + lambda * (b.x - a.x); res.x = a.x + lambda * ( b.x - a.x );
res.y = a.y + lambda * (b.y - a.y); res.y = a.y + lambda * ( b.y - a.y );
return res; 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 ) 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 ) 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 max
#undef sq #undef sq
#undef cu #undef cu
#define sign( x ) ( (x)>0 ? 1 : (x)<0 ? -1 : 0 ) #define sign( x ) ( ( x ) > 0 ? 1 : ( x ) < 0 ? -1 : 0 )
#define abs( a ) ( (a)>0 ? (a) : -(a) ) #define abs( a ) ( ( a ) > 0 ? ( a ) : -( a ) )
#define min( a, b ) ( (a)<(b) ? (a) : (b) ) #define min( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
#define max( a, b ) ( (a)>(b) ? (a) : (b) ) #define max( a, b ) ( ( a ) > ( b ) ? ( a ) : ( b ) )
#define sq( a ) ( (a) * (a) ) #define sq( a ) ( ( a ) * ( a ) )
#define cu( a ) ( (a) * (a) * (a) ) #define cu( a ) ( ( a ) * ( a ) * ( a ) )
#endif /* AUXILIARY_H */ #endif /* AUXILIARY_H */

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
#ifndef BITMAP_H #ifndef BITMAP_H
#define BITMAP_H #define BITMAP_H
#include <string.h>
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <string.h>
/* The bitmap type is defined in potracelib.h */ /* The bitmap type is defined in potracelib.h */
#include "potracelib.h" #include "potracelib.h"
@ -21,58 +21,117 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* some measurements */ /* some measurements */
#define BM_WORDSIZE ( (int) sizeof(potrace_word) ) #define BM_WORDSIZE ( (int) sizeof( potrace_word ) )
#define BM_WORDBITS (8 * BM_WORDSIZE) #define BM_WORDBITS ( 8 * BM_WORDSIZE )
#define BM_HIBIT ( ( (potrace_word) 1 ) << (BM_WORDBITS - 1) ) #define BM_HIBIT ( ( (potrace_word) 1 ) << ( BM_WORDBITS - 1 ) )
#define BM_ALLBITS (~(potrace_word) 0) #define BM_ALLBITS ( ~(potrace_word) 0 )
/* macros for accessing pixel at index (x,y). U* macros omit the /* macros for accessing pixel at index (x,y). U* macros omit the
* bounds check. */ * bounds check. */
#define bm_scanline( bm, y ) ( (bm)->map + (ptrdiff_t) (y) * (ptrdiff_t) (bm)->dy ) #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_index( bm, x, y ) ( &bm_scanline( bm, y )[( x ) / BM_WORDBITS] )
#define bm_mask( x ) ( BM_HIBIT >> ( (x) & (BM_WORDBITS - 1) ) ) #define bm_mask( x ) ( BM_HIBIT >> ( ( x ) & ( BM_WORDBITS - 1 ) ) )
#define bm_range( x, a ) ( (int) (x) >= 0 && (int) (x) < (a) ) #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_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_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_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_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_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_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_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_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_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_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_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. */ /* free the given bitmap. Leaves errno untouched. */
static inline void bm_free( potrace_bitmap_t* bm ) static inline void bm_free( potrace_bitmap_t* bm )
{ {
if( bm ) if( bm && bm->map )
{ {
free( bm->map ); free( bm_base( bm ) );
} }
free( 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. */ * Assumes w, h >= 0. */
static inline potrace_bitmap_t* bm_new( int w, int h ) static inline potrace_bitmap_t* bm_new( int w, int h )
{ {
potrace_bitmap_t* bm; potrace_bitmap_t* bm;
int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1; int dy = w == 0 ? 0 : ( w - 1 ) / BM_WORDBITS + 1;
ptrdiff_t size = (ptrdiff_t) dy * (ptrdiff_t) h * (ptrdiff_t) BM_WORDSIZE; ptrdiff_t size;
/* check for overflow error */ size = getsize( dy, h );
if( size < 0 || (h != 0 && dy != 0 && size / h / dy != BM_WORDSIZE) )
if( size < 0 )
{ {
errno = ENOMEM; errno = ENOMEM;
return NULL; 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 ) if( !bm )
{ {
@ -82,7 +141,7 @@ static inline potrace_bitmap_t* bm_new( int w, int h )
bm->w = w; bm->w = w;
bm->h = h; bm->h = h;
bm->dy = dy; bm->dy = dy;
bm->map = (potrace_word*) malloc( size ); bm->map = (potrace_word*) calloc( 1, size );
if( !bm->map ) 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 ) static inline void bm_clear( potrace_bitmap_t* bm, int c )
{ {
/* Note: if the bitmap was created with bm_new, then it is /* Note: if the bitmap was created with bm_new, then it is
* guaranteed that size will fit into the ptrdiff_t type. */ * 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 ) static inline potrace_bitmap_t* bm_dup( const potrace_bitmap_t* bm )
{ {
potrace_bitmap_t* bm1 = bm_new( bm->w, bm->h ); 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 ) if( !bm1 )
{ {
return NULL; 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; return bm1;
} }
@ -124,14 +190,100 @@ static inline potrace_bitmap_t* bm_dup( const potrace_bitmap_t* bm )
/* invert the given bitmap. */ /* invert the given bitmap. */
static inline void bm_invert( potrace_bitmap_t* bm ) static inline void bm_invert( potrace_bitmap_t* bm )
{ {
ptrdiff_t i; int dy = bm->dy;
ptrdiff_t size = (ptrdiff_t) bm->dy * (ptrdiff_t) bm->h; 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 */ #endif /* BITMAP_H */

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -12,13 +12,24 @@
#include <stdio.h> #include <stdio.h>
#include "bitmap.h" #include "bitmap.h"
#include "bitmap_io.h"
#include "bitops.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_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp );
static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, int magic ); 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 */ /* routines for reading pnm streams */
@ -32,13 +43,13 @@ static int fgetc_ws( FILE* f )
{ {
c = fgetc( f ); c = fgetc( f );
if( c=='#' ) if( c == '#' )
{ {
while( 1 ) while( 1 )
{ {
c = fgetc( f ); c = fgetc( f );
if( c=='\n' || c==EOF ) if( c == '\n' || c == EOF )
{ {
break; break;
} }
@ -46,7 +57,7 @@ static int fgetc_ws( FILE* f )
} }
/* space, tab, line feed, carriage return, form-feed */ /* 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; return c;
} }
@ -69,12 +80,12 @@ static int readnum( FILE* f )
{ {
c = fgetc_ws( f ); c = fgetc_ws( f );
if( c==EOF ) if( c == EOF )
{ {
return -1; return -1;
} }
if( c>='0' && c<='9' ) if( c >= '0' && c <= '9' )
{ {
break; break;
} }
@ -87,12 +98,12 @@ static int readnum( FILE* f )
{ {
c = fgetc( f ); c = fgetc( f );
if( c==EOF ) if( c == EOF )
{ {
break; break;
} }
if( c<'0' || c>'9' ) if( c < '0' || c > '9' )
{ {
ungetc( c, f ); ungetc( c, f );
break; break;
@ -118,12 +129,12 @@ static int readbit( FILE* f )
{ {
c = fgetc_ws( f ); c = fgetc_ws( f );
if( c==EOF ) if( c == EOF )
{ {
return -1; return -1;
} }
if( c>='0' && c<='1' ) if( c >= '0' && c <= '1' )
{ {
break; break;
} }
@ -185,21 +196,23 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
{ {
potrace_bitmap_t* bm; potrace_bitmap_t* bm;
int x, y, i, b, b1, sum; 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 w, h, max;
int realheight; /* in case of incomplete file, keeps track of how
* many scan lines actually contain data */
bm = NULL; bm = NULL;
w = readnum( f ); w = readnum( f );
if( w<0 ) if( w < 0 )
{ {
goto format_error; goto format_error;
} }
h = readnum( f ); h = readnum( f );
if( h<0 ) if( h < 0 )
{ {
goto format_error; goto format_error;
} }
@ -209,11 +222,10 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
if( !bm ) if( !bm )
{ {
return -1; goto std_error;
} }
/* zero it out */ realheight = 0;
bm_clear( bm, 0 );
switch( magic ) switch( magic )
{ {
@ -224,13 +236,15 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
case '1': case '1':
/* read P1 format: PBM ascii */ /* read P1 format: PBM ascii */
for( y = h - 1; y>=0; y-- ) for( y = 0; y < h; y++ )
{ {
for( x = 0; x<w; x++ ) realheight = y + 1;
for( x = 0; x < w; x++ )
{ {
b = readbit( f ); b = readbit( f );
if( b<0 ) if( b < 0 )
{ {
goto eof; goto eof;
} }
@ -246,18 +260,20 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
max = readnum( f ); max = readnum( f );
if( max<1 ) if( max < 1 )
{ {
goto format_error; goto format_error;
} }
for( y = h - 1; y>=0; y-- ) for( y = 0; y < h; y++ )
{ {
for( x = 0; x<w; x++ ) realheight = y + 1;
for( x = 0; x < w; x++ )
{ {
b = readnum( f ); b = readnum( f );
if( b<0 ) if( b < 0 )
{ {
goto eof; goto eof;
} }
@ -273,22 +289,24 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
max = readnum( f ); max = readnum( f );
if( max<1 ) if( max < 1 )
{ {
goto format_error; goto format_error;
} }
for( y = h - 1; y>=0; y-- ) for( y = 0; y < h; y++ )
{ {
for( x = 0; x<w; x++ ) realheight = y + 1;
for( x = 0; x < w; x++ )
{ {
sum = 0; sum = 0;
for( i = 0; i<3; i++ ) for( i = 0; i < 3; i++ )
{ {
b = readnum( f ); b = readnum( f );
if( b<0 ) if( b < 0 )
{ {
goto eof; goto eof;
} }
@ -307,27 +325,28 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
b = fgetc( f ); /* read single white-space character after height */ b = fgetc( f ); /* read single white-space character after height */
if( b==EOF ) if( b == EOF )
{ {
goto format_error; goto format_error;
} }
bpr = (w + 7) / 8; bpr = ( w + 7 ) / 8;
for( y = h - 1; y>=0; y-- ) for( y = 0; y < h; y++ )
{ {
for( i = 0; i<bpr; i++ ) realheight = y + 1;
for( i = 0; i < bpr; i++ )
{ {
b = fgetc( f ); b = fgetc( f );
if( b==EOF ) if( b == EOF )
{ {
goto eof; goto eof;
} }
*bm_index( bm, i * 8, *bm_index( bm, i * 8, y ) |= ( (potrace_word) b )
y ) |= ( (potrace_word) b ) << << ( 8 * ( BM_WORDSIZE - 1 - ( i % BM_WORDSIZE ) ) );
( 8 * ( BM_WORDSIZE - 1 - (i % BM_WORDSIZE) ) );
} }
} }
@ -338,33 +357,35 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
max = readnum( f ); max = readnum( f );
if( max<1 ) if( max < 1 )
{ {
goto format_error; goto format_error;
} }
b = fgetc( f ); /* read single white-space character after max */ b = fgetc( f ); /* read single white-space character after max */
if( b==EOF ) if( b == EOF )
{ {
goto format_error; goto format_error;
} }
for( y = h - 1; y>=0; y-- ) for( y = 0; y < h; y++ )
{ {
for( x = 0; x<w; x++ ) realheight = y + 1;
for( x = 0; x < w; x++ )
{ {
b = fgetc( f ); b = fgetc( f );
if( b==EOF ) if( b == EOF )
goto eof; goto eof;
if( max>=256 ) if( max >= 256 )
{ {
b <<= 8; b <<= 8;
b1 = fgetc( f ); b1 = fgetc( f );
if( b1==EOF ) if( b1 == EOF )
goto eof; goto eof;
b |= b1; b |= b1;
@ -381,39 +402,41 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
max = readnum( f ); max = readnum( f );
if( max<1 ) if( max < 1 )
{ {
goto format_error; goto format_error;
} }
b = fgetc( f ); /* read single white-space character after max */ b = fgetc( f ); /* read single white-space character after max */
if( b==EOF ) if( b == EOF )
{ {
goto format_error; goto format_error;
} }
for( y = h - 1; y>=0; y-- ) for( y = 0; y < h; y++ )
{ {
for( x = 0; x<w; x++ ) realheight = y + 1;
for( x = 0; x < w; x++ )
{ {
sum = 0; sum = 0;
for( i = 0; i<3; i++ ) for( i = 0; i < 3; i++ )
{ {
b = fgetc( f ); b = fgetc( f );
if( b==EOF ) if( b == EOF )
{ {
goto eof; goto eof;
} }
if( max>=256 ) if( max >= 256 )
{ {
b <<= 8; b <<= 8;
b1 = fgetc( f ); b1 = fgetc( f );
if( b1==EOF ) if( b1 == EOF )
goto eof; goto eof;
b |= b1; b |= b1;
@ -429,10 +452,13 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
break; break;
} }
bm_flip( bm );
*bmp = bm; *bmp = bm;
return 0; return 0;
eof: eof:
TRY_STD( bm_resize( bm, realheight ) );
bm_flip( bm );
*bmp = bm; *bmp = bm;
return 1; return 1;
@ -453,6 +479,10 @@ format_error:
} }
return -2; return -2;
std_error:
bm_free( bm );
return -1;
} }
@ -465,22 +495,22 @@ struct bmp_info_s
unsigned int reserved; unsigned int reserved;
unsigned int DataOffset; unsigned int DataOffset;
unsigned int InfoSize; unsigned int InfoSize;
unsigned int w; /* width */ unsigned int w; /* width */
unsigned int h; /* height */ unsigned int h; /* height */
unsigned int Planes; unsigned int Planes;
unsigned int bits; /* bits per sample */ unsigned int bits; /* bits per sample */
unsigned int comp; /* compression mode */ unsigned int comp; /* compression mode */
unsigned int ImageSize; unsigned int ImageSize;
unsigned int XpixelsPerM; unsigned int XpixelsPerM;
unsigned int YpixelsPerM; unsigned int YpixelsPerM;
unsigned int ncolors; /* number of colors in palette */ unsigned int ncolors; /* number of colors in palette */
unsigned int ColorsImportant; unsigned int ColorsImportant;
unsigned int RedMask; unsigned int RedMask;
unsigned int GreenMask; unsigned int GreenMask;
unsigned int BlueMask; unsigned int BlueMask;
unsigned int AlphaMask; unsigned int AlphaMask;
unsigned int ctbits; /* sample size for color table */ unsigned int ctbits; /* sample size for color table */
int topdown; /* top-down mode? */ int topdown; /* top-down mode? */
}; };
typedef struct bmp_info_s bmp_info_t; 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; unsigned int sum = 0;
int b; int b;
for( i = 0; i<n; i++ ) for( i = 0; i < n; i++ )
{ {
b = fgetc( f ); b = fgetc( f );
if( b==EOF ) if( b == EOF )
{ {
return 1; return 1;
} }
sum += b << (8 * i); sum += (unsigned) b << ( 8 * i );
} }
bmp_count += n; bmp_count += n;
@ -529,13 +559,13 @@ static int bmp_pad( FILE* f )
{ {
int c, i, b; int c, i, b;
c = (-bmp_count) & 3; c = ( -bmp_count ) & 3;
for( i = 0; i<c; i++ ) for( i = 0; i < c; i++ )
{ {
b = fgetc( f ); b = fgetc( f );
if( b==EOF ) if( b == EOF )
{ {
return 1; return 1;
} }
@ -556,7 +586,7 @@ static int bmp_forward( FILE* f, int pos )
{ {
b = fgetc( f ); b = fgetc( f );
if( b==EOF ) if( b == EOF )
{ {
return 1; return 1;
} }
@ -569,16 +599,8 @@ static int bmp_forward( FILE* f, int pos )
} }
#define TRY( x ) if( x ) \
goto try_error
#define TRY_EOF( x ) if( x ) \
goto eof
/* correct y-coordinate for top-down format */
#define ycorr( y ) (bmpinfo.topdown ? bmpinfo.h - 1 - y : y)
/* safe colortable access */ /* safe colortable access */
#define COLTABLE( c ) ( (c) < bmpinfo.ncolors ? coltable[(c)] : 0 ) #define COLTABLE( c ) ( ( c ) < bmpinfo.ncolors ? coltable[( c )] : 0 )
/* read BMP stream after magic number. Return values as for bm_read. /* read BMP stream after magic number. Return values as for bm_read.
* We choose to be as permissive as possible, since there are many * We choose to be as permissive as possible, since there are many
@ -601,6 +623,8 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
unsigned int n; unsigned int n;
unsigned int redshift, greenshift, blueshift; unsigned int redshift, greenshift, blueshift;
int col1[2]; int col1[2];
int realheight; /* in case of incomplete file, keeps track of how
* many scan lines actually contain data */
bm_read_error = NULL; bm_read_error = NULL;
bm = NULL; bm = NULL;
@ -616,8 +640,8 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
/* info header */ /* info header */
TRY( bmp_readint( f, 4, &bmpinfo.InfoSize ) ); TRY( bmp_readint( f, 4, &bmpinfo.InfoSize ) );
if( bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64 if( bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64 || bmpinfo.InfoSize == 108
|| bmpinfo.InfoSize == 108 || bmpinfo.InfoSize == 124 ) || bmpinfo.InfoSize == 124 )
{ {
/* Windows or new OS/2 format */ /* Windows or new OS/2 format */
bmpinfo.ctbits = 32; /* sample size in color table */ bmpinfo.ctbits = 32; /* sample size in color table */
@ -632,8 +656,9 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
TRY( bmp_readint( f, 4, &bmpinfo.ncolors ) ); TRY( bmp_readint( f, 4, &bmpinfo.ncolors ) );
TRY( bmp_readint( f, 4, &bmpinfo.ColorsImportant ) ); TRY( bmp_readint( f, 4, &bmpinfo.ColorsImportant ) );
if( bmpinfo.InfoSize >= 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.RedMask ) );
TRY( bmp_readint( f, 4, &bmpinfo.GreenMask ) ); TRY( bmp_readint( f, 4, &bmpinfo.GreenMask ) );
TRY( bmp_readint( f, 4, &bmpinfo.BlueMask ) ); 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 ) if( bmpinfo.h > 0x7fffffff )
{ {
bmpinfo.h = (-bmpinfo.h) & 0xffffffff; bmpinfo.h = ( -bmpinfo.h ) & 0xffffffff;
bmpinfo.topdown = 1; bmpinfo.topdown = 1;
} }
else 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 */ goto format_error; /* can't handle planes */
} }
if( bmpinfo.ncolors == 0 ) if( bmpinfo.ncolors == 0 && bmpinfo.bits <= 8 )
{ {
bmpinfo.ncolors = 1 << bmpinfo.bits; 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. */ /* color table, present only if bmpinfo.bits <= 8. */
if( bmpinfo.bits <= 8 ) if( bmpinfo.bits <= 8 )
{ {
coltable = (int*) calloc( bmpinfo.ncolors, sizeof(int) ); coltable = (int*) calloc( bmpinfo.ncolors, sizeof( int ) );
if( !coltable ) 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 /* NOTE: since we are reading a bitmap, we can immediately convert
* the color table entries to bits. */ * the color table entries to bits. */
for( i = 0; i<bmpinfo.ncolors; i++ ) for( i = 0; i < bmpinfo.ncolors; i++ )
{ {
TRY( bmp_readint( f, bmpinfo.ctbits / 8, &c ) ); TRY( bmp_readint( f, bmpinfo.ctbits / 8, &c ) );
c = ( (c >> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff); c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff );
coltable[i] = (c > 3 * threshold * 255 ? 0 : 1); coltable[i] = ( c > 3 * threshold * 255 ? 0 : 1 );
if( i<2 ) if( i < 2 )
{ {
col1[i] = c; col1[i] = c;
} }
@ -728,8 +753,9 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
} }
/* forward to data */ /* 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 ) ); 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; goto std_error;
} }
/* zero it out */ realheight = 0;
bm_clear( bm, 0 );
switch( bmpinfo.bits + 0x100 * bmpinfo.comp ) switch( bmpinfo.bits + 0x100 * bmpinfo.comp )
{ {
default: default:
goto format_error; goto format_error; break;
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; mask = 0xff;
} }
else else
@ -762,17 +787,17 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
} }
/* raster data */ /* raster data */
for( y = 0; y<bmpinfo.h; y++ ) for( y = 0; y < bmpinfo.h; y++ )
{ {
realheight = y + 1;
bmp_pad_reset(); bmp_pad_reset();
for( i = 0; 8 * i<bmpinfo.w; i++ ) for( i = 0; 8 * i < bmpinfo.w; i++ )
{ {
TRY_EOF( bmp_readint( f, 1, &b ) ); TRY_EOF( bmp_readint( f, 1, &b ) );
b ^= mask; b ^= mask;
*bm_index( bm, i * 8, *bm_index( bm, i * 8, y ) |= ( (potrace_word) b )
ycorr( y ) ) |= ( (potrace_word) b ) << << ( 8 * ( BM_WORDSIZE - 1 - ( i % BM_WORDSIZE ) ) );
( 8 * ( BM_WORDSIZE - 1 - (i % BM_WORDSIZE) ) );
} }
TRY( bmp_pad( f ) ); TRY( bmp_pad( f ) );
@ -788,25 +813,26 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
case 0x007: case 0x007:
case 0x008: case 0x008:
for( y = 0; y<bmpinfo.h; y++ ) for( y = 0; y < bmpinfo.h; y++ )
{ {
realheight = y + 1;
bmp_pad_reset(); bmp_pad_reset();
bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */ bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */
n = 0; /* number of bits currently in bitbuffer */ n = 0; /* number of bits currently in bitbuffer */
for( x = 0; x<bmpinfo.w; x++ ) for( x = 0; x < bmpinfo.w; x++ )
{ {
if( n < bmpinfo.bits ) if( n < bmpinfo.bits )
{ {
TRY_EOF( bmp_readint( f, 1, &b ) ); TRY_EOF( bmp_readint( f, 1, &b ) );
bitbuf |= b << (INTBITS - 8 - n); bitbuf |= b << ( INTBITS - 8 - n );
n += 8; n += 8;
} }
b = bitbuf >> (INTBITS - bmpinfo.bits); b = bitbuf >> ( INTBITS - bmpinfo.bits );
bitbuf <<= bmpinfo.bits; bitbuf <<= bmpinfo.bits;
n -= bmpinfo.bits; n -= bmpinfo.bits;
BM_UPUT( bm, x, ycorr( y ), COLTABLE( b ) ); BM_UPUT( bm, x, y, COLTABLE( b ) );
} }
TRY( bmp_pad( f ) ); 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 0x018: /* 24-bit encoding */
case 0x020: /* 32-bit encoding */ case 0x020: /* 32-bit encoding */
for( y = 0; y<bmpinfo.h; y++ ) for( y = 0; y < bmpinfo.h; y++ )
{ {
realheight = y + 1;
bmp_pad_reset(); bmp_pad_reset();
for( x = 0; x<bmpinfo.w; x++ ) for( x = 0; x < bmpinfo.w; x++ )
{ {
TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) ); TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
c = ( (c >> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff); c = ( ( c >> 16 ) & 0xff ) + ( ( c >> 8 ) & 0xff ) + ( c & 0xff );
BM_UPUT( bm, x, ycorr( y ), c > 3 * threshold * 255 ? 0 : 1 ); BM_UPUT( bm, x, y, c > 3 * threshold * 255 ? 0 : 1 );
} }
TRY( bmp_pad( f ) ); TRY( bmp_pad( f ) );
@ -841,21 +868,28 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
break; break;
case 0x320: /* 32-bit encoding with bitfields */ case 0x320: /* 32-bit encoding with bitfields */
if( bmpinfo.RedMask == 0 || bmpinfo.GreenMask == 0 || bmpinfo.BlueMask == 0 )
{
goto format_error;
}
redshift = lobit( bmpinfo.RedMask ); redshift = lobit( bmpinfo.RedMask );
greenshift = lobit( bmpinfo.GreenMask ); greenshift = lobit( bmpinfo.GreenMask );
blueshift = lobit( bmpinfo.BlueMask ); blueshift = lobit( bmpinfo.BlueMask );
for( y = 0; y<bmpinfo.h; y++ ) for( y = 0; y < bmpinfo.h; y++ )
{ {
realheight = y + 1;
bmp_pad_reset(); bmp_pad_reset();
for( x = 0; x<bmpinfo.w; x++ ) for( x = 0; x < bmpinfo.w; x++ )
{ {
TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) ); TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
c = ( (c & bmpinfo.RedMask) >> redshift ) + c = ( ( c & bmpinfo.RedMask ) >> redshift )
( (c & bmpinfo.GreenMask) >> greenshift ) + + ( ( c & bmpinfo.GreenMask ) >> greenshift )
( (c & bmpinfo.BlueMask) >> blueshift ); + ( ( c & bmpinfo.BlueMask ) >> blueshift );
BM_UPUT( bm, x, ycorr( y ), c > 3 * threshold * 255 ? 0 : 1 ); BM_UPUT( bm, x, y, c > 3 * threshold * 255 ? 0 : 1 );
} }
TRY( bmp_pad( f ) ); 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, &b ) ); /* opcode */
TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */ TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
if( b>0 ) if( b > 0 )
{ {
/* repeat count */ /* repeat count */
col[0] = COLTABLE( (c >> 4) & 0xf ); col[0] = COLTABLE( ( c >> 4 ) & 0xf );
col[1] = COLTABLE( c & 0xf ); col[1] = COLTABLE( c & 0xf );
for( i = 0; i<b && x<bmpinfo.w; i++ ) for( i = 0; i < b && x < bmpinfo.w; i++ )
{ {
if( x>=bmpinfo.w ) if( x >= bmpinfo.w )
{ {
x = 0; x = 0;
y++; y++;
} }
if( y>=bmpinfo.h ) if( x >= bmpinfo.w || y >= bmpinfo.h )
{ {
break; break;
} }
BM_UPUT( bm, x, ycorr( y ), col[i & 1] ); realheight = y + 1;
BM_PUT( bm, x, y, col[i & 1] );
x++; x++;
} }
} }
@ -917,29 +952,30 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
else else
{ {
/* verbatim segment */ /* verbatim segment */
for( i = 0; i<c; i++ ) for( i = 0; i < c; i++ )
{ {
if( (i & 1)==0 ) if( ( i & 1 ) == 0 )
{ {
TRY_EOF( bmp_readint( f, 1, &b ) ); TRY_EOF( bmp_readint( f, 1, &b ) );
} }
if( x>=bmpinfo.w ) if( x >= bmpinfo.w )
{ {
x = 0; x = 0;
y++; y++;
} }
if( y>=bmpinfo.h ) if( x >= bmpinfo.w || y >= bmpinfo.h )
{ {
break; 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++; x++;
} }
if( (c + 1) & 2 ) if( ( c + 1 ) & 2 )
{ {
/* pad to 16-bit boundary */ /* pad to 16-bit boundary */
TRY_EOF( bmp_readint( f, 1, &b ) ); 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, &b ) ); /* opcode */
TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */ TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
if( b>0 ) if( b > 0 )
{ {
/* repeat count */ /* repeat count */
for( i = 0; i<b; i++ ) for( i = 0; i < b; i++ )
{ {
if( x>=bmpinfo.w ) if( x >= bmpinfo.w )
{ {
x = 0; x = 0;
y++; y++;
} }
if( y>=bmpinfo.h ) if( x >= bmpinfo.w || y >= bmpinfo.h )
{ {
break; break;
} }
BM_UPUT( bm, x, ycorr( y ), COLTABLE( c ) ); realheight = y + 1;
BM_PUT( bm, x, y, COLTABLE( c ) );
x++; x++;
} }
} }
@ -1000,22 +1037,23 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
else else
{ {
/* verbatim segment */ /* verbatim segment */
for( i = 0; i<c; i++ ) for( i = 0; i < c; i++ )
{ {
TRY_EOF( bmp_readint( f, 1, &b ) ); TRY_EOF( bmp_readint( f, 1, &b ) );
if( x>=bmpinfo.w ) if( x >= bmpinfo.w )
{ {
x = 0; x = 0;
y++; y++;
} }
if( y>=bmpinfo.h ) if( x >= bmpinfo.w || y >= bmpinfo.h )
{ {
break; break;
} }
BM_PUT( bm, x, ycorr( y ), COLTABLE( b ) ); realheight = y + 1;
BM_PUT( bm, x, y, COLTABLE( b ) );
x++; x++;
} }
@ -1035,11 +1073,24 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
bmp_forward( f, bmpinfo.FileSize ); bmp_forward( f, bmpinfo.FileSize );
free( coltable ); free( coltable );
if( bmpinfo.topdown )
{
bm_flip( bm );
}
*bmp = bm; *bmp = bm;
return 0; return 0;
eof: eof:
TRY_STD( bm_resize( bm, realheight ) );
free( coltable ); free( coltable );
if( bmpinfo.topdown )
{
bm_flip( bm );
}
*bmp = bm; *bmp = bm;
return 1; return 1;
@ -1072,17 +1123,16 @@ void bm_writepbm( FILE* f, potrace_bitmap_t* bm )
w = bm->w; w = bm->w;
h = bm->h; h = bm->h;
bpr = (w + 7) / 8; bpr = ( w + 7 ) / 8;
fprintf( f, "P4\n%d %d\n", w, h ); 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<bpr; i++ ) for( i = 0; i < bpr; i++ )
{ {
c = c = ( *bm_index( bm, i * 8, y ) >> ( 8 * ( BM_WORDSIZE - 1 - ( i % BM_WORDSIZE ) ) ) )
( *bm_index( bm, i * 8, & 0xff;
y ) >> ( 8 * ( BM_WORDSIZE - 1 - (i % BM_WORDSIZE) ) ) ) & 0xff;
fputc( c, f ); fputc( c, f );
} }
} }
@ -1101,17 +1151,17 @@ int bm_print( FILE* f, potrace_bitmap_t* bm )
int sw, sh; int sw, sh;
sw = bm->w < 79 ? bm->w : 79; 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; xx<sw; xx++ ) for( xx = 0; xx < sw; xx++ )
{ {
d = 0; d = 0;
for( x = xx * bm->w / 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 ) ) if( BM_GET( bm, x, y ) )
{ {

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -7,8 +7,8 @@
#ifndef BITMAP_IO_H #ifndef BITMAP_IO_H
#define BITMAP_IO_H #define BITMAP_IO_H
#include <stdio.h>
#include "bitmap.h" #include "bitmap.h"
#include <stdio.h>
/* Note that bitmaps are stored bottom to top, i.e., the first /* Note that bitmaps are stored bottom to top, i.e., the first
* scanline is the bottom-most one */ * scanline is the bottom-most one */

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
/* bits.h: this file defines some macros for bit manipulations. We /* bits.h: this file defines some macros for bit manipulations. We
* provide a generic implementation, as well as machine- and * provide a generic implementation, as well as machine- and
* compiler-specific fast implementations */ * compiler-specific fast implementations */
@ -22,19 +21,19 @@
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* machine specific macros */ /* machine specific macros */
#if defined(HAVE_I386) #if defined( HAVE_I386 )
static inline unsigned int lobit( unsigned int x ) static inline unsigned int lobit( unsigned int x )
{ {
unsigned int res; unsigned int res;
asm ("bsf %1,%0\n\t" asm ( "bsf %1,%0\n\t"
"jnz 0f\n\t" "jnz 0f\n\t"
"movl $32,%0\n" "movl $32,%0\n"
"0:" "0:"
: "=r" (res) : "=r" ( res )
: "r" (x) : "r" ( x )
: "cc"); : "cc" );
return res; return res;
} }
@ -43,13 +42,13 @@ static inline unsigned int hibit( unsigned int x )
{ {
unsigned int res; unsigned int res;
asm ("bsr %1,%0\n\t" asm ( "bsr %1,%0\n\t"
"jnz 0f\n\t" "jnz 0f\n\t"
"movl $-1,%0\n" "movl $-1,%0\n"
"0:" "0:"
: "=r" (res) : "=r" ( res )
: "r" (x) : "r" ( x )
: "cc"); : "cc" );
return res + 1; return res + 1;
} }

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -12,12 +12,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "potracelib.h"
#include "lists.h"
#include "curve.h" #include "curve.h"
#include "lists.h"
#include "potracelib.h"
#define SAFE_CALLOC( var, n, typ ) \ #define SAFE_CALLOC( var, n, typ ) \
if( ( var = (typ*) calloc( n, sizeof(typ) ) ) == NULL ) \ if( ( var = (typ*) calloc( n, sizeof( typ ) ) ) == NULL ) \
goto calloc_error goto calloc_error
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -29,9 +29,9 @@ path_t* path_new( void )
privpath_t* priv = NULL; privpath_t* priv = NULL;
SAFE_CALLOC( p, 1, path_t ); SAFE_CALLOC( p, 1, path_t );
memset( p, 0, sizeof(path_t) ); memset( p, 0, sizeof( path_t ) );
SAFE_CALLOC( priv, 1, privpath_t ); SAFE_CALLOC( priv, 1, privpath_t );
memset( priv, 0, sizeof(privpath_t) ); memset( priv, 0, sizeof( privpath_t ) );
p->priv = priv; p->priv = priv;
return p; return p;
@ -97,7 +97,7 @@ typedef dpoint_t dpoint3_t[3];
* Return 0 on success, 1 on error with errno set. */ * Return 0 on success, 1 on error with errno set. */
int privcurve_init( privcurve_t* curve, int n ) int privcurve_init( privcurve_t* curve, int n )
{ {
memset( curve, 0, sizeof(privcurve_t) ); memset( curve, 0, sizeof( privcurve_t ) );
curve->n = n; curve->n = n;
SAFE_CALLOC( curve->tag, n, int ); SAFE_CALLOC( curve->tag, n, int );
SAFE_CALLOC( curve->c, n, dpoint3_t ); SAFE_CALLOC( curve->c, n, dpoint3_t );

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -6,16 +6,21 @@
#include <config.h> #include <config.h>
#endif #endif
#include <cstdint>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h> #ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include "potracelib.h"
#include "curve.h"
#include "lists.h"
#include "bitmap.h" #include "bitmap.h"
#include "curve.h"
#include "decompose.h" #include "decompose.h"
#include "lists.h"
#include "potracelib.h"
#include "progress.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), /* non-linear sequence: constant term of inverse in GF(8),
* mod x^8+x^4+x^3+x+1 */ * 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,
0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 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, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 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, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 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,
0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 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, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 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,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 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,
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, 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,
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, 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, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
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 /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
* 5-bit sequence */ * 5-bit sequence */
z = ( (0x04b3e375 * x) ^ y ) * 0x05a8ef93; z = ( ( 0x04b3e375 * x ) ^ y ) * 0x05a8ef93;
z = t[z & 0xff] ^ t[(z >> 8) & 0xff] ^ t[(z >> 16) & 0xff] ^ t[(z >> 24) & 0xff]; z = t[z & 0xff] ^ t[( z >> 8 ) & 0xff] ^ t[( z >> 16 ) & 0xff] ^ t[( z >> 24 ) & 0xff];
return z; return z;
} }
@ -60,9 +64,9 @@ static void bm_clearexcess( potrace_bitmap_t* bm )
if( bm->w % BM_WORDBITS != 0 ) 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; y<bm->h; y++ ) for( y = 0; y < bm->h; y++ )
{ {
*bm_index( bm, bm->w, y ) &= mask; *bm_index( bm, bm->w, y ) &= mask;
} }
@ -80,13 +84,13 @@ typedef struct bbox_s bbox_t;
* than clearing the whole bitmap) */ * than clearing the whole bitmap) */
static void clear_bm_with_bbox( potrace_bitmap_t* bm, bbox_t* bbox ) static void clear_bm_with_bbox( potrace_bitmap_t* bm, bbox_t* bbox )
{ {
int imin = (bbox->x0 / BM_WORDBITS); int imin = ( bbox->x0 / BM_WORDBITS );
int imax = ( (bbox->x1 + BM_WORDBITS - 1) / BM_WORDBITS ); int imax = ( ( bbox->x1 + BM_WORDBITS - 1 ) / BM_WORDBITS );
int i, y; int i, y;
for( y = bbox->y0; y<bbox->y1; y++ ) for( y = bbox->y0; y < bbox->y1; y++ )
{ {
for( i = imin; i<imax; i++ ) for( i = imin; i < imax; i++ )
{ {
bm_scanline( bm, y )[i] = 0; bm_scanline( bm, y )[i] = 0;
} }
@ -103,11 +107,12 @@ static int majority( potrace_bitmap_t* bm, int x, int y )
{ {
int i, a, ct; int i, a, ct;
for( i = 2; i<5; i++ ) /* check at "radius" i */ for( i = 2; i < 5; i++ )
{ {
/* check at "radius" i */
ct = 0; ct = 0;
for( a = -i + 1; a<=i - 1; a++ ) for( a = -i + 1; a <= i - 1; a++ )
{ {
ct += BM_GET( bm, x + a, y + i - 1 ) ? 1 : -1; ct += BM_GET( bm, x + a, y + i - 1 ) ? 1 : -1;
ct += BM_GET( bm, x + i - 1, y + a - 1 ) ? 1 : -1; ct += BM_GET( bm, x + i - 1, y + a - 1 ) ? 1 : -1;
@ -115,11 +120,11 @@ static int majority( potrace_bitmap_t* bm, int x, int y )
ct += BM_GET( bm, x - i, y + a ) ? 1 : -1; ct += BM_GET( bm, x - i, y + a ) ? 1 : -1;
} }
if( ct>0 ) if( ct > 0 )
{ {
return 1; return 1;
} }
else if( ct<0 ) else if( ct < 0 )
{ {
return 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 ) static void xor_to_ref( potrace_bitmap_t* bm, int x, int y, int xa )
{ {
int xhi = x & - BM_WORDBITS; 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; int i;
if( xhi<xa ) if( xhi < xa )
{ {
for( i = xhi; i < xa; i += BM_WORDBITS ) for( i = xhi; i < xa; i += BM_WORDBITS )
{ {
@ -159,7 +164,7 @@ static void xor_to_ref( potrace_bitmap_t* bm, int x, int y, int xa )
* a<<(b&31). I spent hours looking for this bug. */ * a<<(b&31). I spent hours looking for this bug. */
if( xlo ) if( xlo )
{ {
*bm_index( bm, xhi, y ) ^= ( BM_ALLBITS << (BM_WORDBITS - xlo) ); *bm_index( bm, xhi, y ) ^= ( BM_ALLBITS << ( BM_WORDBITS - xlo ) );
} }
} }
@ -176,8 +181,9 @@ static void xor_path( potrace_bitmap_t* bm, path_t* p )
{ {
int xa, x, y, k, y1; int xa, x, y, k, y1;
if( p->priv->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; return;
} }
@ -185,7 +191,7 @@ static void xor_path( potrace_bitmap_t* bm, path_t* p )
xa = p->priv->pt[0].x & - BM_WORDBITS; xa = p->priv->pt[0].x & - BM_WORDBITS;
for( k = 0; k<p->priv->len; k++ ) for( k = 0; k < p->priv->len; k++ )
{ {
x = p->priv->pt[k].x; x = p->priv->pt[k].x;
y = p->priv->pt[k].y; 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->x0 = INT_MAX;
bbox->x1 = 0; bbox->x1 = 0;
for( k = 0; k<p->priv->len; k++ ) for( k = 0; k < p->priv->len; k++ )
{ {
x = p->priv->pt[k].x; x = p->priv->pt[k].x;
y = p->priv->pt[k].y; y = p->priv->pt[k].y;
@ -248,7 +254,8 @@ static void setbbox_path( bbox_t* bbox, path_t* p )
* of turnpolicies. */ * of turnpolicies. */
static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int turnpolicy ) 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; int c, d, tmp;
point_t* pt, * pt1; point_t* pt, * pt1;
path_t* p = NULL; 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 ) while( 1 )
{ {
/* add point to path */ /* add point to path */
if( len>=size ) if( len >= size )
{ {
size += 100; size += 100;
size = (int) (1.3 * size); size = (int) ( 1.3 * size );
pt1 = (point_t*) realloc( pt, size * sizeof(point_t) ); pt1 = (point_t*) realloc( pt, size * sizeof( point_t ) );
if( !pt1 ) 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; area += x * diry;
/* path complete? */ /* path complete? */
if( x==x0 && y==y0 ) if( x == x0 && y == y0 )
{ {
break; break;
} }
/* determine next direction */ /* determine next direction */
c = 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 ); 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 if( turnpolicy == POTRACE_TURNPOLICY_RIGHT
|| (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+') || ( turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+' )
|| (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-') || ( turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-' )
|| ( turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand( x, y ) ) || ( turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand( x, y ) )
|| ( turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority( bm, x, y ) ) || ( turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority( bm, x, y ) )
|| ( turnpolicy == POTRACE_TURNPOLICY_MINORITY && !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; diry = tmp;
} }
} }
else if( c ) /* right turn */ else if( c )
{ {
/* right turn */
tmp = dirx; tmp = dirx;
dirx = diry; dirx = diry;
diry = -tmp; diry = -tmp;
} }
else if( !d ) /* left turn */ else if( !d )
{ {
/* left turn */
tmp = dirx; tmp = dirx;
dirx = -diry; dirx = -diry;
diry = tmp; 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->pt = pt;
p->priv->len = len; p->priv->len = len;
p->area = area; p->area = area <= INT_MAX ? area : INT_MAX; /* avoid overflow */
p->sign = sign; p->sign = sign;
return p; return p;
@ -519,11 +529,11 @@ static int findnext( potrace_bitmap_t* bm, int* xp, int* yp )
int y; int y;
int x0; 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; x<bm->w; x += BM_WORDBITS ) for( x = x0; x < bm->w && x >= 0; x += (unsigned) BM_WORDBITS )
{ {
if( *bm_index( bm, x, y ) ) 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 * in. Returns 0 on success with plistp set, or -1 on error with errno
* set. */ * set. */
int bm_to_pathlist( const potrace_bitmap_t* bm, int bm_to_pathlist( const potrace_bitmap_t* bm, path_t** plistp, const potrace_param_t* param,
path_t** plistp,
const potrace_param_t* param,
progress_t* progress ) progress_t* progress )
{ {
int x; int x;
@ -588,7 +596,7 @@ int bm_to_pathlist( const potrace_bitmap_t* bm,
/* calculate the path */ /* calculate the path */
p = findpath( bm1, x, y + 1, sign, param->turnpolicy ); p = findpath( bm1, x, y + 1, sign, param->turnpolicy );
if( p==NULL ) if( p == NULL )
{ {
goto error; goto error;
} }
@ -606,8 +614,9 @@ int bm_to_pathlist( const potrace_bitmap_t* bm,
list_insert_beforehook( p, plist_hook ); 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 ); progress_update( 1 - y / (double) bm1->h, progress );
} }
} }

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
#ifndef DECOMPOSE_H #ifndef DECOMPOSE_H
#define DECOMPOSE_H #define DECOMPOSE_H
#include "curve.h"
#include "potracelib.h" #include "potracelib.h"
#include "progress.h" #include "progress.h"
#include "curve.h"
int bm_to_pathlist( const potrace_bitmap_t* bm, int bm_to_pathlist( const potrace_bitmap_t* bm, path_t** plistp, const potrace_param_t* param,
path_t** plistp,
const potrace_param_t* param,
progress_t* progress ); progress_t* progress );
#endif /* DECOMPOSE_H */ #endif /* DECOMPOSE_H */

File diff suppressed because it is too large Load Diff

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
#ifndef GREYMAP_H #ifndef GREYMAP_H
#define GREYMAP_H #define GREYMAP_H
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h>
/* type for greymap samples */
typedef signed short int gm_sample_t;
/* internal format for greymaps. Note: in this format, rows are /* internal format for greymaps. Note: in this format, rows are
* ordered from bottom to top. The pixels in each row are given from * ordered from bottom to top. The pixels in each row are given from
* left to right. */ * left to right. */
struct greymap_s struct greymap_s
{ {
int w; /* width, in pixels */ int w; /* width, in pixels */
int h; /* height, in pixels */ int h; /* height, in pixels */
signed short int* map; /* raw data, w*h values */ 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; typedef struct greymap_s greymap_t;
/* macros for accessing pixel at index (x,y). Note that the origin is /* macros for accessing pixel at index (x,y). Note that the origin is
* in the *lower* left corner. U* macros omit the bounds check. */ * 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_scanline( gm, y ) ( ( gm )->map + (ptrdiff_t) ( y ) * (ptrdiff_t) ( gm )->dy )
#define gm_safe( gm, x, \ #define gm_index( gm, x, y ) ( gm_scanline( gm, y ) + ( x ) )
y ) ( (int) (x)>=0 && (int) (x)<(gm)->w && (int) (y)>=0 \ #define gm_safe( gm, x, y ) \
&& (int) (y)<(gm)->h ) ( (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_bound( x, m ) ( ( x ) < 0 ? 0 : ( x ) >= ( m ) ? (m) - 1 : ( x ) )
#define GM_UGET( gm, x, y ) ( *gm_index( gm, x, y ) ) #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_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_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_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_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_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_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_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 /* modes for cutting off out-of-range values. The following names
* refer to winding numbers. I.e., make a pixel black if winding * 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_free( greymap_t* gm );
void gm_clear( greymap_t* gm, int b ); void gm_clear( greymap_t* gm, int b );
int gm_read( FILE* f, greymap_t** gmp ); 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_writepgm( FILE* f,
int gm_print( FILE* f, greymap_t* gm ); greymap_t* gm,
const char* comment,
int raw,
int mode,
double gamma );
int gm_print( FILE* f, greymap_t* gm );
#endif /* GREYMAP_H */ #endif /* GREYMAP_H */

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
#ifndef _PS_LISTS_H #ifndef _PS_LISTS_H
#define _PS_LISTS_H #define _PS_LISTS_H
@ -31,148 +30,168 @@
* such as "if (...) macro(...); else ...". If we didn't use this obscure * such as "if (...) macro(...); else ...". If we didn't use this obscure
* trick, we'd have to omit the ";" in such cases. */ * trick, we'd have to omit the ";" in such cases. */
#define MACRO_BEGIN do { #define MACRO_BEGIN \
#define MACRO_END } \ do \
{
#define MACRO_END \
} \
while( 0 ) while( 0 )
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* macros for singly-linked lists */ /* macros for singly-linked lists */
/* traverse list. At the end, elt is set to NULL. */ /* 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 /* set elt to the first element of list satisfying boolean condition
* c, or NULL if not found */ * 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 ) \ MACRO_BEGIN list_forall( elt, list ) if( c ) \
break; \ break; \
MACRO_END MACRO_END
/* like forall, except also set hook for elt. */ /* like forall, except also set hook for elt. */
#define list_forall2( elt, list, hook ) \ #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. */ /* 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 ) \ MACRO_BEGIN list_forall2( elt, list, hook ) if( c ) \
break; \ break; \
MACRO_END MACRO_END
/* same, except only use hook. */ /* same, except only use hook. */
#define _list_forall_hook( list, hook ) \ #define _list_forall_hook( list, hook ) for( hook = &list; *hook != NULL; hook = &( *hook )->next )
for( hook = &list; *hook!=NULL; hook = &(*hook)->next )
/* same, except only use hook. Note: c may only refer to *hook, not elt. */ /* 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 ) \ MACRO_BEGIN _list_forall_hook( list, hook ) if( c ) \
break; \ break; \
MACRO_END MACRO_END
/* insert element after hook */ /* insert element after hook */
#define list_insert_athook( elt, 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 */ /* insert element before hook */
#define list_insert_beforehook( elt, 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. /* unlink element after hook, let elt be unlinked element, or NULL.
* hook remains. */ * hook remains. */
#define list_unlink_athook( list, elt, hook ) \ #define list_unlink_athook( list, elt, hook ) \
MACRO_BEGIN \ MACRO_BEGIN \
elt = hook ? *hook : NULL; if( elt ) { *hook = elt->next; elt->next = NULL; } \ elt = hook ? *hook : NULL; \
if( elt ) \
{ \
*hook = elt->next; \
elt->next = NULL; \
} \
MACRO_END MACRO_END
/* unlink the specific element, if it is in the list. Otherwise, set /* unlink the specific element, if it is in the list. Otherwise, set
* elt to NULL */ * elt to NULL */
#define list_unlink( listtype, list, elt ) \ #define list_unlink( listtype, list, elt ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * *_hook; \ listtype * *_hook; \
_list_find_hook( list, *_hook==elt, _hook ); \ _list_find_hook( list, *_hook == elt, _hook ); \
list_unlink_athook( list, elt, _hook ); \ list_unlink_athook( list, elt, _hook ); \
MACRO_END MACRO_END
/* prepend elt to list */ /* prepend elt to list */
#define list_prepend( list, elt ) \ #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. */ /* append elt to list. */
#define list_append( listtype, list, elt ) \ #define list_append( listtype, list, elt ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * *_hook; \ listtype * *_hook; \
_list_forall_hook( list, _hook ) {} \ _list_forall_hook( list, _hook ) \
list_insert_athook( elt, _hook ); \ { \
} \
list_insert_athook( elt, _hook ); \
MACRO_END MACRO_END
/* unlink the first element that satisfies the condition. */ /* unlink the first element that satisfies the condition. */
#define list_unlink_cond( listtype, list, elt, c ) \ #define list_unlink_cond( listtype, list, elt, c ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * *_hook; \ listtype * *_hook; \
list_find2( elt, list, c, _hook ); \ list_find2( elt, list, c, _hook ); \
list_unlink_athook( list, elt, _hook ); \ list_unlink_athook( list, elt, _hook ); \
MACRO_END MACRO_END
/* let elt be the nth element of the list, starting to count from 0. /* let elt be the nth element of the list, starting to count from 0.
* Return NULL if out of bounds. */ * Return NULL if out of bounds. */
#define list_nth( elt, list, n ) \ #define list_nth( elt, list, n ) \
MACRO_BEGIN \ MACRO_BEGIN \
int _x; /* only evaluate n once */ \ int _x; /* only evaluate n once */ \
for( _x = (n), elt = list; _x && elt; _x--, elt = elt->next ) {} \ for( _x = ( n ), elt = list; _x && elt; _x--, elt = elt->next ) \
{ \
} \
MACRO_END MACRO_END
/* let elt be the nth element of the list, starting to count from 0. /* let elt be the nth element of the list, starting to count from 0.
* Return NULL if out of bounds. */ * Return NULL if out of bounds. */
#define list_nth_hook( elt, list, n, hook ) \ #define list_nth_hook( elt, list, n, hook ) \
MACRO_BEGIN \ MACRO_BEGIN \
int _x; /* only evaluate n once */ \ int _x; /* only evaluate n once */ \
for( _x = (n), elt = list, hook = &list; _x && elt; \ for( _x = ( n ), elt = list, hook = &list; _x && elt; \
_x--, hook = &elt->next, elt = elt->next ) {} \ _x--, hook = &elt->next, elt = elt->next ) \
{ \
} \
MACRO_END MACRO_END
/* set n to the length of the list */ /* set n to the length of the list */
#define list_length( listtype, list, n ) \ #define list_length( listtype, list, n ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * _elt; \ listtype * _elt; \
n = 0; \ n = 0; \
list_forall( _elt, list ) \ list_forall( _elt, list ) n++; \
n++; \
MACRO_END MACRO_END
/* set n to the index of the first element satisfying cond, or -1 if /* 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. */ * none found. Also set elt to the element, or NULL if none found. */
#define list_index( list, n, elt, c ) \ #define list_index( list, n, elt, c ) \
MACRO_BEGIN \ MACRO_BEGIN \
n = 0; \ n = 0; \
list_forall( elt, list ) { \ list_forall( elt, list ) \
if( c ) \ { \
if( c ) \
break; \ break; \
n++; \ n++; \
} \ } \
if( !elt ) \ if( !elt ) \
n = -1; \ n = -1; \
MACRO_END MACRO_END
/* set n to the number of elements in the list that satisfy condition c */ /* set n to the number of elements in the list that satisfy condition c */
#define list_count( list, n, elt, c ) \ #define list_count( list, n, elt, c ) \
MACRO_BEGIN \ MACRO_BEGIN \
n = 0; \ n = 0; \
list_forall( elt, list ) { \ list_forall( elt, list ) \
if( c ) \ { \
if( c ) \
n++; \ n++; \
} \ } \
MACRO_END MACRO_END
/* let elt be each element of the list, unlinked. At the end, set list=NULL. */ /* let elt be each element of the list, unlinked. At the end, set list=NULL. */
#define list_forall_unlink( elt, list ) \ #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) */ /* reverse a list (efficient) */
#define list_reverse( listtype, list ) \ #define list_reverse( listtype, list ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * _list1 = NULL, *elt; \ listtype * _list1 = NULL, *elt; \
list_forall_unlink( elt, list ) \ list_forall_unlink( elt, list ) list_prepend( _list1, elt ); \
list_prepend( _list1, elt ); \ list = _list1; \
list = _list1; \
MACRO_END MACRO_END
/* insert the element ELT just before the first element TMP of the /* 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 * Note: it is much more efficient to construct a list with
* list_prepend and then order it with list_merge_sort, than to * list_prepend and then order it with list_merge_sort, than to
* construct it with list_insert_ordered. */ * construct it with list_insert_ordered. */
#define list_insert_ordered( listtype, list, elt, tmp, cond ) \ #define list_insert_ordered( listtype, list, elt, tmp, cond ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * *_hook; \ listtype * *_hook; \
_list_find_hook( list, ( tmp = *_hook, (cond) ), _hook ); \ _list_find_hook( list, ( tmp = *_hook, ( cond ) ), _hook ); \
list_insert_athook( elt, _hook ); \ list_insert_athook( elt, _hook ); \
MACRO_END MACRO_END
@ -200,12 +219,11 @@
* "less than" condition, each segment of equal elements will retain * "less than" condition, each segment of equal elements will retain
* the original order. The latter is slower but sometimes * the original order. The latter is slower but sometimes
* prettier. Average running time: n*n/2. */ * prettier. Average running time: n*n/2. */
#define list_sort( listtype, list, a, b, cond ) \ #define list_sort( listtype, list, a, b, cond ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * _newlist = NULL; \ listtype * _newlist = NULL; \
list_forall_unlink( a, list ) \ list_forall_unlink( a, list ) list_insert_ordered( listtype, _newlist, a, b, cond ); \
list_insert_ordered( listtype, _newlist, a, b, cond ); \ list = _newlist; \
list = _newlist; \
MACRO_END MACRO_END
/* a much faster sort algorithm (merge sort, n log n worst case). It /* 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 * component. Note there is no curious reversal of order of equal
* elements as for list_sort. */ * elements as for list_sort. */
#define list_mergesort( listtype, list, a, b, cond ) \ #define list_mergesort( listtype, list, a, b, cond ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * _elt, **_hook1; \ listtype * _elt, **_hook1; \
\ \
for( _elt = list; _elt; _elt = _elt->next1 ) { \ for( _elt = list; _elt; _elt = _elt->next1 ) \
_elt->next1 = _elt->next; \ { \
_elt->next = NULL; \ _elt->next1 = _elt->next; \
} \ _elt->next = NULL; \
do { \ } \
_hook1 = &(list); \ do \
while( (a = *_hook1) != NULL && (b = a->next1) != NULL ) { \ { \
_elt = b->next1; \ _hook1 = &( list ); \
_list_merge_cond( listtype, a, b, cond, *_hook1 ); \ while( ( a = *_hook1 ) != NULL && ( b = a->next1 ) != NULL ) \
_hook1 = &( (*_hook1)->next1 ); \ { \
*_hook1 = _elt; \ _elt = b->next1; \
} \ _list_merge_cond( listtype, a, b, cond, *_hook1 ); \
_hook1 = &( ( *_hook1 )->next1 ); \
*_hook1 = _elt; \
} \
} \ } \
while( _hook1 != &(list) ); \ while( _hook1 != &( list ) ); \
MACRO_END MACRO_END
/* merge two sorted lists. Store result at &result */ /* merge two sorted lists. Store result at &result */
#define _list_merge_cond( listtype, a, b, cond, result ) \ #define _list_merge_cond( listtype, a, b, cond, result ) \
MACRO_BEGIN \ MACRO_BEGIN \
listtype * *_hook; \ listtype * *_hook; \
_hook = &(result); \ _hook = &( result ); \
while( 1 ) { \ while( 1 ) \
if( a==NULL ) { \ { \
*_hook = b; \ if( a == NULL ) \
break; \ { \
} \ *_hook = b; \
else if( b==NULL ) { \ break; \
*_hook = a; \ } \
break; \ else if( b == NULL ) \
} \ { \
else if( cond ) { \ *_hook = a; \
*_hook = a; \ break; \
_hook = &(a->next); \ } \
a = a->next; \ else if( cond ) \
} \ { \
else { \ *_hook = a; \
*_hook = b; \ _hook = &( a->next ); \
_hook = &(b->next); \ a = a->next; \
b = b->next; \ } \
} \ else \
} \ { \
*_hook = b; \
_hook = &( b->next ); \
b = b->next; \
} \
} \
MACRO_END MACRO_END
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* macros for doubly-linked lists */ /* macros for doubly-linked lists */
#define dlist_append( head, end, elt ) \ #define dlist_append( head, end, elt ) \
MACRO_BEGIN \ MACRO_BEGIN \
elt->prev = end; \ elt->prev = end; \
elt->next = NULL; \ elt->next = NULL; \
if( end ) { \ if( end ) \
end->next = elt; \ { \
} \ end->next = elt; \
else { \ } \
head = elt; \ else \
} \ { \
head = elt; \
} \
end = elt; \ end = elt; \
MACRO_END MACRO_END
/* let elt be each element of the list, unlinked. At the end, set list=NULL. */ /* let elt be each element of the list, unlinked. At the end, set list=NULL. */
#define dlist_forall_unlink( elt, head, end ) \ #define dlist_forall_unlink( elt, head, end ) \
for( elt = head; \ for( elt = head; \
elt ? (head = elt->next, elt->next = NULL, elt->prev = NULL), 1 : (end = NULL, 0); \ elt ? ( head = elt->next, elt->next = NULL, elt->prev = NULL ), 1 : ( end = NULL, 0 ); \
elt = head ) elt = head )
/* unlink the first element of the list */ /* unlink the first element of the list */
#define dlist_unlink_first( head, end, elt ) \ #define dlist_unlink_first( head, end, elt ) \
MACRO_BEGIN \ MACRO_BEGIN \
elt = head; \ elt = head; \
if( head ) { \ if( head ) \
{ \
head = head->next; \ head = head->next; \
if( head ) { \ if( head ) \
head->prev = NULL; \ { \
} \ head->prev = NULL; \
else { \ } \
end = NULL; \ else \
} \ { \
end = NULL; \
} \
elt->prev = NULL; \ elt->prev = NULL; \
elt->next = NULL; \ elt->next = NULL; \
} \ } \
MACRO_END MACRO_END
#endif /* _PS_LISTS_H */ #endif /* _PS_LISTS_H */

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -8,7 +8,7 @@
#define PLATFORM_H #define PLATFORM_H
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include "config.h" #include <config.h>
#endif #endif
/* in Windows, set all file i/o to binary */ /* in Windows, set all file i/o to binary */

View File

@ -1 +1 @@
#define POTRACELIB_VERSION "potracelib 1.13" #define POTRACELIB_VERSION "potracelib 1.15"

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -9,12 +9,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "potracelib.h"
#include "curve.h" #include "curve.h"
#include "decompose.h" #include "decompose.h"
#include "trace.h" #include "potracelib.h"
#include "progress.h" #include "progress.h"
#include <potrace_version.h> #include "trace.h"
/* default parameters */ /* default parameters */
static const potrace_param_t param_default = static const potrace_param_t param_default =
@ -38,14 +37,14 @@ potrace_param_t* potrace_param_default( void )
{ {
potrace_param_t* p; potrace_param_t* p;
p = (potrace_param_t*) malloc( sizeof(potrace_param_t) ); p = (potrace_param_t*) malloc( sizeof( potrace_param_t ) );
if( !p ) if( !p )
{ {
return NULL; return NULL;
} }
memcpy( p, &param_default, sizeof(potrace_param_t) ); memcpy( p, &param_default, sizeof( potrace_param_t ) );
return p; 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; prog.d_prev = param->progress.min;
/* allocate state object */ /* allocate state object */
st = (potrace_state_t*) malloc( sizeof(potrace_state_t) ); st = (potrace_state_t*) malloc( sizeof( potrace_state_t ) );
if( !st ) if( !st )
{ {
@ -128,6 +127,7 @@ void potrace_param_free( potrace_param_t* p )
} }
#include "potrace_version.h"
const char* potrace_version( void ) const char* potrace_version( void )
{ {
return POTRACELIB_VERSION; return POTRACELIB_VERSION;

View File

@ -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 * 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. */ * 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 */ /* structure to hold progress bar callback data */
struct potrace_progress_s 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 */ void* data; /* callback function's private data */
double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */ double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */
double epsilon; /* granularity: can skip smaller increments */ double epsilon; /* granularity: can skip smaller increments */
@ -58,9 +58,9 @@ typedef unsigned long potrace_word;
* bit of scanline(n)[0]. */ * bit of scanline(n)[0]. */
struct potrace_bitmap_s struct potrace_bitmap_s
{ {
int w, h; /* width and height, in pixels */ int w, h; /* width and height, in pixels */
int dy; /* words per scanline (not bytes) */ int dy; /* words per scanline (not bytes) */
potrace_word* map; /* raw data, dy*h words */ potrace_word* map; /* raw data, dy*h words */
}; };
typedef struct potrace_bitmap_s potrace_bitmap_t; typedef struct potrace_bitmap_s potrace_bitmap_t;
@ -128,9 +128,8 @@ potrace_param_t* potrace_param_default( void );
/* free parameter set */ /* free parameter set */
void potrace_param_free( potrace_param_t* p ); void potrace_param_free( potrace_param_t* p );
/* trace a bitmap*/ /* trace a bitmap */
potrace_state_t* potrace_trace( const potrace_param_t* param, potrace_state_t* potrace_trace( const potrace_param_t* param, const potrace_bitmap_t* bm );
const potrace_bitmap_t* bm );
/* free a Potrace state */ /* free a Potrace state */
void potrace_state_free( potrace_state_t* st ); void potrace_state_free( potrace_state_t* st );
@ -139,7 +138,7 @@ void potrace_state_free( potrace_state_t* st );
* of potracelib */ * of potracelib */
const char* potrace_version( void ); const char* potrace_version( void );
#ifdef __cplusplus #ifdef __cplusplus
} /* end of extern "C" */ } /* end of extern "C" */
#endif #endif

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -14,12 +14,12 @@
/* structure to hold progress bar callback data */ /* structure to hold progress bar callback data */
struct progress_s 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 */ void* data; /* callback function's private data */
double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */ double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */
double epsilon; /* granularity: can skip smaller increments */ double epsilon; /* granularity: can skip smaller increments */
double b; /* upper limit of subrange in superrange units */ double b; /* upper limit of subrange in superrange units */
double d_prev; /* previous value of d */ double d_prev; /* previous value of d */
}; };
typedef struct progress_s progress_t; 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 ) 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 ) 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; prog->d_prev = d_scaled;
} }
} }
@ -59,8 +59,8 @@ static inline void progress_subrange_start( double a,
return; return;
} }
min = prog->min * (1 - a) + prog->max * a; min = prog->min * ( 1 - a ) + prog->max * a;
max = prog->min * (1 - b) + prog->max * b; max = prog->min * ( 1 - b ) + prog->max * b;
if( max - min < prog->epsilon ) if( max - min < prog->epsilon )
{ {
@ -71,7 +71,7 @@ static inline void progress_subrange_start( double a,
sub->callback = prog->callback; sub->callback = prog->callback;
sub->data = prog->data; sub->data = prog->data;
sub->epsilon = prog->epsilon; sub->epsilon = prog->epsilon;
sub->min = min; sub->min = min;
sub->max = max; sub->max = max;
sub->d_prev = prog->d_prev; sub->d_prev = prog->d_prev;

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
@ -6,14 +6,14 @@
#include <config.h> #include <config.h>
#endif #endif
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
#include <string.h> #include <string.h>
#include "render.h"
#include "greymap.h"
#include "auxiliary.h" #include "auxiliary.h"
#include "greymap.h"
#include "render.h"
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
/* routines for anti-aliased rendering of curves */ /* routines for anti-aliased rendering of curves */
@ -50,16 +50,16 @@ render_t* render_new( greymap_t* gm )
{ {
render_t* rm; render_t* rm;
rm = (render_t*) malloc( sizeof(render_t) ); rm = (render_t*) malloc( sizeof( render_t ) );
if( !rm ) if( !rm )
{ {
return NULL; return NULL;
} }
memset( rm, 0, sizeof(render_t) ); memset( rm, 0, sizeof( render_t ) );
rm->gm = gm; 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 ) if( !rm->incrow_buf )
{ {
@ -67,7 +67,6 @@ render_t* render_new( greymap_t* gm )
return NULL; return NULL;
} }
memset( rm->incrow_buf, 0, gm->h * sizeof(int) );
return rm; return rm;
} }
@ -89,7 +88,7 @@ void render_close( render_t* rm )
render_lineto( rm, rm->x0, rm->y0 ); 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); */ /* 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 ) if( x0 < x )
{ {
for( i = x0; i<x; i++ ) for( i = x0; i < x; i++ )
{ {
GM_INC( rm->gm, i, y, -b ); GM_INC( rm->gm, i, y, -b );
} }
} }
else else
{ {
for( i = x; i<x0; i++ ) for( i = x; i < x0; i++ )
{ {
GM_INC( rm->gm, i, y, b ); GM_INC( rm->gm, i, y, b );
} }
@ -165,8 +164,8 @@ void render_lineto( render_t* rm, double x2, double y2 )
int x2i, y2i; int x2i, y2i;
double t0 = 2, s0 = 2; double t0 = 2, s0 = 2;
int sn, tn; int sn, tn;
double ss = 2, ts = 2; double ss = 2, ts = 2;
double r0, r1; double r0, r1;
int i, j; int i, j;
int rxi, ryi; int rxi, ryi;
int s; int s;
@ -179,27 +178,27 @@ void render_lineto( render_t* rm, double x2, double y2 )
if( sn ) if( sn )
{ {
s0 = ( (x2>rm->x1 ? rm->x1i + 1 : rm->x1i) - rm->x1 ) / (x2 - rm->x1); s0 = ( ( x2 > rm->x1 ? rm->x1i + 1 : rm->x1i ) - rm->x1 ) / ( x2 - rm->x1 );
ss = fabs( 1.0 / (x2 - rm->x1) ); ss = fabs( 1.0 / ( x2 - rm->x1 ) );
} }
if( tn ) if( tn )
{ {
t0 = ( (y2>rm->y1 ? rm->y1i + 1 : rm->y1i) - rm->y1 ) / (y2 - rm->y1); t0 = ( ( y2 > rm->y1 ? rm->y1i + 1 : rm->y1i ) - rm->y1 ) / ( y2 - rm->y1 );
ts = fabs( 1.0 / (y2 - rm->y1) ); ts = fabs( 1.0 / ( y2 - rm->y1 ) );
} }
r0 = 0; r0 = 0;
i = 0; i = 0;
j = 0; j = 0;
rxi = rm->x1i; rxi = rm->x1i;
ryi = rm->y1i; ryi = rm->y1i;
while( i<sn || j<tn ) while( i < sn || j < tn )
{ {
if( j>=tn || (i<sn && s0 + i * ss < t0 + j * ts) ) if( j >= tn || ( i < sn && s0 + i * ss < t0 + j * ts ) )
{ {
r1 = s0 + i * ss; r1 = s0 + i * ss;
i++; 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) */ /* render line from r0 to r1 segment of (rm->x1,rm->y1)..(x2,y2) */
/* move point to r1 */ /* move point to r1 */
rm->a1 += (r1 - r0) * (y2 - rm->y1) * rm->a1 += ( r1 - r0 ) * ( y2 - rm->y1 )
( rxi + 1 - ( (r0 + r1) / 2.0 * (x2 - rm->x1) + rm->x1 ) ); * ( rxi + 1 - ( ( r0 + r1 ) / 2.0 * ( x2 - rm->x1 ) + rm->x1 ) );
/* move point across pixel boundary */ /* move point across pixel boundary */
if( s && x2>rm->x1 ) if( s && x2 > rm->x1 )
{ {
GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 ); GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 );
rm->a1 = 0; rm->a1 = 0;
rxi++; 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 ); GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 );
rm->a1 = 0; rm->a1 = 0;
incrow( rm, rxi + 1, ryi, 255 ); incrow( rm, rxi + 1, ryi, 255 );
ryi++; 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 ); GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 );
rm->a1 = 0; rm->a1 = 0;
rxi--; rxi--;
} }
else if( !s && y2<=rm->y1 ) else if( !s && y2 <= rm->y1 )
{ {
GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 ); GM_INC( rm->gm, rxi, ryi, rm->a1 * 255 );
rm->a1 = 0; rm->a1 = 0;
@ -254,8 +253,8 @@ void render_lineto( render_t* rm, double x2, double y2 )
/* move point to (x2,y2) */ /* move point to (x2,y2) */
r1 = 1; r1 = 1;
rm->a1 += (r1 - r0) * (y2 - rm->y1) * rm->a1 += ( r1 - r0 ) * ( y2 - rm->y1 )
( rxi + 1 - ( (r0 + r1) / 2.0 * (x2 - rm->x1) + rm->x1 ) ); * ( rxi + 1 - ( ( r0 + r1 ) / 2.0 * ( x2 - rm->x1 ) + rm->x1 ) );
rm->x1i = x2i; rm->x1i = x2i;
rm->y1i = y2i; 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; e2 = 8 * delta <= dd ? 8 * delta / dd : 1;
epsilon = sqrt( e2 ); /* necessary interval size */ 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( render_lineto( rm, x1 * cu( 1 - t ) + 3 * x2 * sq( 1 - t ) * t
t ) + x4 * cu( 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 * y1 * cu( 1 - t ) + 3 * y2 * sq( 1 - t ) * t + 3 * y3 * ( 1 - t ) * sq( t )
cu( t ) ); + y4 * cu( t ) );
} }
render_lineto( rm, x4, y4 ); render_lineto( rm, x4, y4 );

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
#ifndef RENDER_H #ifndef RENDER_H
#define RENDER_H #define RENDER_H
@ -13,8 +12,8 @@ struct render_s
greymap_t* gm; greymap_t* gm;
double x0, y0, x1, y1; double x0, y0, x1, y1;
int x0i, y0i, x1i, y1i; int x0i, y0i, x1i, y1i;
double a0, a1; double a0, a1;
int* incrow_buf; int* incrow_buf;
}; };
typedef struct render_s render_t; typedef struct render_s render_t;

File diff suppressed because it is too large Load Diff

View File

@ -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 * 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. */ * by the GNU General Public License. See the file COPYING for details. */
#ifndef TRACE_H #ifndef TRACE_H
#define TRACE_H #define TRACE_H
#include "curve.h"
#include "potracelib.h" #include "potracelib.h"
#include "progress.h" #include "progress.h"
#include "curve.h"
int process_path( path_t* plist, const potrace_param_t* param, progress_t* progress ); int process_path( path_t* plist, const potrace_param_t* param, progress_t* progress );