Potrace library: update version from 1.8 to 1.12

This commit is contained in:
jean-pierre charras 2015-12-03 16:46:17 +01:00
parent 9b4d12653e
commit 23a0dddea9
21 changed files with 1530 additions and 1004 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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,14 +8,16 @@
#ifndef AUXILIARY_H
#define AUXILIARY_H
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#include "config.h"
#endif
/* ---------------------------------------------------------------------- */
/* point arithmetic */
#include <potracelib.h>
#include "potracelib.h"
struct point_s
{
@ -49,7 +51,6 @@ static inline dpoint_t interval( double lambda, dpoint_t a, dpoint_t b )
/* ---------------------------------------------------------------------- */
/* some useful macros. Note: the "mod" macro works correctly for
* negative a. Also note that the test for a>=n, while redundant,
* speeds up the mod function by 70% in the average case (significant

View File

@ -1,19 +1,16 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/* The bitmap type is defined in potracelib.h */
#include <potracelib.h>
#include "potracelib.h"
/* The present file defines some convenient macros and static inline
* functions for accessing bitmaps. Since they only produce inline
@ -31,7 +28,7 @@
/* macros for accessing pixel at index (x,y). U* macros omit the
* bounds check. */
#define bm_scanline( bm, y ) ( (bm)->map + (y) * (bm)->dy )
#define bm_scanline( bm, y ) ( (bm)->map + (ssize_t) (y) * (ssize_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) )
@ -54,30 +51,44 @@ static inline void bm_free( potrace_bitmap_t* bm )
{
free( bm->map );
}
free( bm );
}
/* return new un-initialized bitmap. NULL with errno on error */
/* return new un-initialized bitmap. 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 + BM_WORDBITS - 1) / BM_WORDBITS;
int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1;
ssize_t size = (ssize_t) dy * (ssize_t) h * (ssize_t) BM_WORDSIZE;
/* check for overflow error */
if( size < 0 || size / h / dy != BM_WORDSIZE )
{
errno = ENOMEM;
return NULL;
}
bm = (potrace_bitmap_t*) malloc( sizeof(potrace_bitmap_t) );
if( !bm )
{
return NULL;
}
bm->w = w;
bm->h = h;
bm->dy = dy;
bm->map = (potrace_word*) malloc( dy * h * BM_WORDSIZE );
bm->map = (potrace_word*) malloc( size );
if( !bm->map )
{
free( bm );
return NULL;
}
return bm;
}
@ -85,7 +96,11 @@ static inline potrace_bitmap_t* bm_new( int w, int h )
/* clear the given bitmap. Set all bits to c. */
static inline void bm_clear( potrace_bitmap_t* bm, int c )
{
memset( bm->map, c ? -1 : 0, bm->dy * bm->h * BM_WORDSIZE );
/* Note: if the bitmap was created with bm_new, then it is
* guaranteed that size will fit into the ssize_t type. */
ssize_t size = (ssize_t) bm->dy * (ssize_t) bm->h * (ssize_t) BM_WORDSIZE;
memset( bm->map, c ? -1 : 0, size );
}
@ -93,12 +108,14 @@ static inline void bm_clear( potrace_bitmap_t* bm, int c )
static inline potrace_bitmap_t* bm_dup( const potrace_bitmap_t* bm )
{
potrace_bitmap_t* bm1 = bm_new( bm->w, bm->h );
ssize_t size = (ssize_t) bm->dy * (ssize_t) bm->h * (ssize_t) BM_WORDSIZE;
if( !bm1 )
{
return NULL;
}
memcpy( bm1->map, bm->map, bm->dy * bm->h * BM_WORDSIZE );
memcpy( bm1->map, bm->map, size );
return bm1;
}
@ -106,9 +123,10 @@ 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 )
{
int i;
ssize_t i;
ssize_t size = (ssize_t) bm->dy * (ssize_t) bm->h;
for( i = 0; i < bm->dy * bm->h; i++ )
for( i = 0; i < size; i++ )
{
bm->map[i] ^= BM_ALLBITS;
}

View File

@ -1,14 +1,14 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: bitmap_io.c 147 2007-04-09 00:44:09Z selinger $ */
/* Routines for manipulating bitmaps, including reading pbm files. */
#include <stdio.h>
#include <bitmap.h>
#include "bitmap.h"
#include "bitops.h"
#define INTBITS ( 8 * sizeof(int) )
@ -27,17 +27,20 @@ static int fgetc_ws( FILE* f )
while( 1 )
{
c = fgetc( f );
if( c=='#' )
{
while( 1 )
{
c = fgetc( f );
if( c=='\n' || c==EOF )
{
break;
}
}
}
/* space, tab, line feed, carriage return, form-feed */
if( c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12 )
{
@ -61,10 +64,12 @@ static int readnum( FILE* f )
while( 1 )
{
c = fgetc_ws( f );
if( c==EOF )
{
return -1;
}
if( c>='0' && c<='9' )
{
break;
@ -73,18 +78,22 @@ static int readnum( FILE* f )
/* first digit is already in c */
acc = c - '0';
while( 1 )
{
c = fgetc( f );
if( c==EOF )
{
break;
}
if( c<'0' || c>'9' )
{
ungetc( c, f );
break;
}
acc *= 10;
acc += c - '0';
}
@ -104,10 +113,12 @@ static int readbit( FILE* f )
while( 1 )
{
c = fgetc_ws( f );
if( c==EOF )
{
return -1;
}
if( c>='0' && c<='1' )
{
break;
@ -140,19 +151,24 @@ int bm_read( FILE* f, double threshold, potrace_bitmap_t** bmp )
* by the PNM standard, but there is no harm in being lenient. */
magic[0] = fgetc_ws( f );
if( magic[0] == EOF )
{
return -3;
}
magic[1] = fgetc( f );
if( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' )
{
return bm_readbody_pnm( f, threshold, bmp, magic[1] );
}
if( magic[0] == 'B' && magic[1] == 'M' )
{
return bm_readbody_bmp( f, threshold, bmp );
}
return -4;
}
@ -171,12 +187,14 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
bm = NULL;
w = readnum( f );
if( w<0 )
{
goto format_error;
}
h = readnum( f );
if( h<0 )
{
goto format_error;
@ -184,6 +202,7 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
/* allocate bitmap */
bm = bm_new( w, h );
if( !bm )
{
return -1;
@ -206,10 +225,12 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
for( x = 0; x<w; x++ )
{
b = readbit( f );
if( b<0 )
{
goto eof;
}
BM_UPUT( bm, x, y, b );
}
}
@ -220,6 +241,7 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
/* read P2 format: PGM ascii */
max = readnum( f );
if( max<1 )
{
goto format_error;
@ -230,10 +252,12 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
for( x = 0; x<w; x++ )
{
b = readnum( f );
if( b<0 )
{
goto eof;
}
BM_UPUT( bm, x, y, b > threshold * max ? 0 : 1 );
}
}
@ -244,6 +268,7 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
/* read P3 format: PPM ascii */
max = readnum( f );
if( max<1 )
{
goto format_error;
@ -254,13 +279,16 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
for( x = 0; x<w; x++ )
{
sum = 0;
for( i = 0; i<3; i++ )
{
b = readnum( f );
if( b<0 )
{
goto eof;
}
sum += b;
}
@ -274,6 +302,7 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
/* read P4 format: PBM raw */
b = fgetc( f ); /* read single white-space character after height */
if( b==EOF )
{
goto format_error;
@ -286,10 +315,12 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
for( i = 0; i<bpr; i++ )
{
b = fgetc( f );
if( b==EOF )
{
goto eof;
}
*bm_index( bm, i * 8,
y ) |= ( (potrace_word) b ) <<
( 8 * ( BM_WORDSIZE - 1 - (i % BM_WORDSIZE) ) );
@ -302,12 +333,14 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
/* read P5 format: PGM raw */
max = readnum( f );
if( max<1 )
{
goto format_error;
}
b = fgetc( f ); /* read single white-space character after max */
if( b==EOF )
{
goto format_error;
@ -318,16 +351,21 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
for( x = 0; x<w; x++ )
{
b = fgetc( f );
if( b==EOF )
goto eof;
if( max>=256 )
{
b <<= 8;
b1 = fgetc( f );
if( b1==EOF )
goto eof;
b |= b1;
}
BM_UPUT( bm, x, y, b > threshold * max ? 0 : 1 );
}
}
@ -338,12 +376,14 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
/* read P6 format: PPM raw */
max = readnum( f );
if( max<1 )
{
goto format_error;
}
b = fgetc( f ); /* read single white-space character after max */
if( b==EOF )
{
goto format_error;
@ -354,21 +394,27 @@ static int bm_readbody_pnm( FILE* f, double threshold, potrace_bitmap_t** bmp, i
for( x = 0; x<w; x++ )
{
sum = 0;
for( i = 0; i<3; i++ )
{
b = fgetc( f );
if( b==EOF )
{
goto eof;
}
if( max>=256 )
{
b <<= 8;
b1 = fgetc( f );
if( b1==EOF )
goto eof;
b |= b1;
}
sum += b;
}
@ -388,6 +434,7 @@ eof:
format_error:
bm_free( bm );
if( magic == '1' || magic == '4' )
{
bm_read_error = "invalid pbm file";
@ -400,6 +447,7 @@ format_error:
{
bm_read_error = "invalid ppm file";
}
return -2;
}
@ -423,7 +471,12 @@ struct bmp_info_s
unsigned int YpixelsPerM;
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? */
};
typedef struct bmp_info_s bmp_info_t;
@ -443,10 +496,12 @@ static int bmp_readint( FILE* f, int n, unsigned int* p )
for( i = 0; i<n; i++ )
{
b = fgetc( f );
if( b==EOF )
{
return 1;
}
sum += b << (8 * i);
}
@ -471,9 +526,11 @@ static int bmp_pad( FILE* f )
int c, i, b;
c = (-bmp_count) & 3;
for( i = 0; i<c; i++ )
{
b = fgetc( f );
if( b==EOF )
{
return 1;
@ -494,10 +551,12 @@ static int bmp_forward( FILE* f, int pos )
while( bmp_pos < pos )
{
b = fgetc( f );
if( b==EOF )
{
return 1;
}
bmp_pos++;
bmp_count++;
}
@ -511,6 +570,9 @@ static int bmp_forward( FILE* f, int pos )
#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)
/* read BMP stream after magic number. Return values as for bm_read.
* We choose to be as permissive as possible, since there are many
* programs out there which produce BMP. For instance, ppmtobmp can
@ -530,6 +592,7 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
int col[2];
unsigned int bitbuf;
unsigned int n;
unsigned int redshift, greenshift, blueshift;
int col1[2];
bm_read_error = NULL;
@ -545,7 +608,9 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
/* info header */
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 == 124 )
{
/* Windows or new OS/2 format */
bmpinfo.ctbits = 32; /* sample size in color table */
@ -559,6 +624,34 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
TRY( bmp_readint( f, 4, &bmpinfo.YpixelsPerM ) );
TRY( bmp_readint( f, 4, &bmpinfo.ncolors ) );
TRY( bmp_readint( f, 4, &bmpinfo.ColorsImportant ) );
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 ) );
TRY( bmp_readint( f, 4, &bmpinfo.AlphaMask ) );
}
if( bmpinfo.w > 0x7fffffff )
{
goto format_error;
}
if( bmpinfo.h > 0x7fffffff )
{
bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
bmpinfo.topdown = 1;
}
else
{
bmpinfo.topdown = 0;
}
if( bmpinfo.h > 0x7fffffff )
{
goto format_error;
}
}
else if( bmpinfo.InfoSize == 12 )
{
@ -570,13 +663,20 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
TRY( bmp_readint( f, 2, &bmpinfo.bits ) );
bmpinfo.comp = 0;
bmpinfo.ncolors = 0;
bmpinfo.topdown = 0;
}
else
{
goto format_error;
}
/* forward to color table (i.e., if bmpinfo.InfoSize == 64) */
if( bmpinfo.comp == 3 && bmpinfo.InfoSize < 108 )
{
/* bitfield feature is only understood with V4 and V5 format */
goto format_error;
}
/* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
TRY( bmp_forward( f, 14 + bmpinfo.InfoSize ) );
if( bmpinfo.Planes != 1 )
@ -593,7 +693,8 @@ 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*) malloc( bmpinfo.ncolors * sizeof(int) );
coltable = (int*) calloc( bmpinfo.ncolors, sizeof(int) );
if( !coltable )
{
goto std_error;
@ -606,6 +707,7 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
TRY( bmp_readint( f, bmpinfo.ctbits / 8, &c ) );
c = ( (c >> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff);
coltable[i] = (c > 3 * threshold * 255 ? 0 : 1);
if( i<2 )
{
col1[i] = c;
@ -621,6 +723,7 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
/* allocate bitmap */
bm = bm_new( bmpinfo.w, bmpinfo.h );
if( !bm )
{
goto std_error;
@ -636,6 +739,7 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
break;
case 0x001: /* monochrome palette */
if( col1[0] < col1[1] ) /* make the darker color black */
{
mask = 0xff;
@ -649,12 +753,13 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
for( y = 0; y<bmpinfo.h; y++ )
{
bmp_pad_reset();
for( i = 0; 8 * i<bmpinfo.w; i++ )
{
TRY_EOF( bmp_readint( f, 1, &b ) );
b ^= mask;
*bm_index( bm, i * 8,
y ) |= ( (potrace_word) b ) <<
ycorr( y ) ) |= ( (potrace_word) b ) <<
( 8 * ( BM_WORDSIZE - 1 - (i % BM_WORDSIZE) ) );
}
@ -670,11 +775,13 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
case 0x006:
case 0x007:
case 0x008:
for( y = 0; y<bmpinfo.h; y++ )
{
bmp_pad_reset();
bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */
n = 0; /* number of bits currently in bitbuffer */
for( x = 0; x<bmpinfo.w; x++ )
{
if( n < bmpinfo.bits )
@ -683,10 +790,11 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
bitbuf |= b << (INTBITS - 8 - n);
n += 8;
}
b = bitbuf >> (INTBITS - bmpinfo.bits);
bitbuf <<= bmpinfo.bits;
n -= bmpinfo.bits;
BM_UPUT( bm, x, y, coltable[b] );
BM_UPUT( bm, x, ycorr( y ), coltable[b] );
}
TRY( bmp_pad( f ) );
@ -695,7 +803,6 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
break;
case 0x010: /* 16-bit encoding */
/* can't do this format because it is not well-documented and I
* don't have any samples */
bm_read_error = "cannot handle bmp 16-bit coding";
@ -704,14 +811,39 @@ 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<bmpinfo.h; y++ )
{
bmp_pad_reset();
for( x = 0; x<bmpinfo.w; x++ )
{
TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
c = ( (c >> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff);
BM_UPUT( bm, x, y, c > 3 * threshold * 255 ? 0 : 1 );
BM_UPUT( bm, x, ycorr( y ), c > 3 * threshold * 255 ? 0 : 1 );
}
TRY( bmp_pad( f ) );
}
break;
case 0x320: /* 32-bit encoding with bitfields */
redshift = lobit( bmpinfo.RedMask );
greenshift = lobit( bmpinfo.GreenMask );
blueshift = lobit( bmpinfo.BlueMask );
for( y = 0; y<bmpinfo.h; y++ )
{
bmp_pad_reset();
for( x = 0; x<bmpinfo.w; x++ )
{
TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
c = ( (c & bmpinfo.RedMask) >> redshift ) +
( (c & bmpinfo.GreenMask) >> greenshift ) +
( (c & bmpinfo.BlueMask) >> blueshift );
BM_UPUT( bm, x, ycorr( y ), c > 3 * threshold * 255 ? 0 : 1 );
}
TRY( bmp_pad( f ) );
@ -722,15 +854,18 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
case 0x204: /* 4-bit runlength compressed encoding (RLE4) */
x = 0;
y = 0;
while( 1 )
{
TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */
TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
if( b>0 )
{
/* repeat count */
col[0] = coltable[(c >> 4) & 0xf];
col[1] = coltable[c & 0xf];
for( i = 0; i<b && x<bmpinfo.w; i++ )
{
if( x>=bmpinfo.w )
@ -738,11 +873,13 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
BM_UPUT( bm, x, y, col[i & 1] );
BM_UPUT( bm, x, ycorr( y ), col[i & 1] );
x++;
}
}
@ -774,16 +911,19 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
{
TRY_EOF( bmp_readint( f, 1, &b ) );
}
if( x>=bmpinfo.w )
{
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
BM_PUT( bm, x, y, coltable[( b >> ( 4 - 4 * (i & 1) ) ) & 0xf] );
BM_PUT( bm, x, ycorr( y ), coltable[( b >> ( 4 - 4 * (i & 1) ) ) & 0xf] );
x++;
}
@ -800,10 +940,12 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
case 0x108: /* 8-bit runlength compressed encoding (RLE8) */
x = 0;
y = 0;
while( 1 )
{
TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */
TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
if( b>0 )
{
/* repeat count */
@ -814,11 +956,13 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
BM_UPUT( bm, x, y, coltable[c] );
BM_UPUT( bm, x, ycorr( y ), coltable[c] );
x++;
}
}
@ -847,16 +991,19 @@ static int bm_readbody_bmp( FILE* f, double threshold, potrace_bitmap_t** bmp )
for( i = 0; i<c; i++ )
{
TRY_EOF( bmp_readint( f, 1, &b ) );
if( x>=bmpinfo.w )
{
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
BM_PUT( bm, x, y, coltable[b] );
BM_PUT( bm, x, ycorr( y ), coltable[b] );
x++;
}
@ -888,10 +1035,12 @@ format_error:
try_error:
free( coltable );
free( bm );
if( !bm_read_error )
{
bm_read_error = "invalid bmp file";
}
return -2;
std_error:
@ -914,6 +1063,7 @@ void bm_writepbm( FILE* f, potrace_bitmap_t* bm )
bpr = (w + 7) / 8;
fprintf( f, "P4\n%d %d\n", w, h );
for( y = h - 1; y>=0; y-- )
{
for( i = 0; i<bpr; i++ )
@ -924,8 +1074,6 @@ void bm_writepbm( FILE* f, potrace_bitmap_t* bm )
fputc( c, f );
}
}
return;
}
@ -948,6 +1096,7 @@ int bm_print( FILE* f, potrace_bitmap_t* bm )
for( xx = 0; xx<sw; xx++ )
{
d = 0;
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++ )

View File

@ -1,20 +1,19 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: bitmap_io.h 147 2007-04-09 00:44:09Z selinger $ */
/* bitmap input/output functions */
#ifndef BITMAP_IO_H
#define BITMAP_IO_H
#include <stdio.h>
#include <bitmap.h>
#include "bitmap.h"
/* Note that bitmaps are stored bottom to top, i.e., the first
* scanline is the bottom-most one */
extern char* bm_read_error;
extern const char* bm_read_error;
int bm_read( FILE* f, double blacklevel, potrace_bitmap_t** bmp );
void bm_writepbm( FILE* f, potrace_bitmap_t* bm );

View File

@ -1,50 +1,102 @@
/* Copyright (C) 2001-2007 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. */
/* Copyright (C) 2001-2015 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. */
/* $Id: bitops.h 147 2007-04-09 00:44:09Z selinger $ */
/* bits.h: this file defines some macros for bit manipulations. We
provide a generic implementation */
* provide a generic implementation, as well as machine- and
* compiler-specific fast implementations */
/* lobit: return the position of the rightmost "1" bit of an int, or
32 if none. hibit: return 1 + the position of the leftmost "1" bit
of an int, or 0 if none. Note: these functions work on 32-bit
integers. */
* 32 if none. hibit: return 1 + the position of the leftmost "1" bit
* of an int, or 0 if none. Note: these functions work on 32-bit
* integers. */
#ifndef BITOPS_H
#define BITOPS_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#include "config.h"
#endif
/* generic macros */
/* ---------------------------------------------------------------------- */
/* machine specific macros */
static inline unsigned int lobit(unsigned int x) {
#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");
return res;
}
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");
return res + 1;
}
/* ---------------------------------------------------------------------- */
#else /* generic macros */
static inline unsigned int lobit( unsigned int x )
{
unsigned int res = 32;
while (x & 0xffffff) {
while( x & 0xffffff )
{
x <<= 8;
res -= 8;
}
while (x) {
while( x )
{
x <<= 1;
res -= 1;
}
return res;
}
static inline unsigned int hibit(unsigned int x) {
static inline unsigned int hibit( unsigned int x )
{
unsigned int res = 0;
while (x > 0xff) {
while( x > 0xff )
{
x >>= 8;
res += 8;
}
while (x) {
while( x )
{
x >>= 1;
res += 1;
}
return res;
}
#endif
#endif /* BITOPS_H */

View File

@ -1,21 +1,20 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: curve.c 147 2007-04-09 00:44:09Z selinger $ */
/* private part of the path and curve data structures */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <potracelib.h>
#include <lists.h>
#include <curve.h>
#include "potracelib.h"
#include "lists.h"
#include "curve.h"
#define SAFE_MALLOC( var, n, typ ) \
if( ( var = (typ*) malloc( (n)* sizeof(typ) ) ) == NULL ) \
goto malloc_error
#define SAFE_CALLOC( var, n, typ ) \
if( ( var = (typ*) calloc( n, sizeof(typ) ) ) == NULL ) \
goto calloc_error
/* ---------------------------------------------------------------------- */
/* allocate and free path objects */
@ -25,14 +24,14 @@ path_t* path_new( void )
path_t* p = NULL;
privpath_t* priv = NULL;
SAFE_MALLOC( p, 1, path_t );
SAFE_CALLOC( p, 1, path_t );
memset( p, 0, sizeof(path_t) );
SAFE_MALLOC( priv, 1, privpath_t );
SAFE_CALLOC( priv, 1, privpath_t );
memset( priv, 0, sizeof(privpath_t) );
p->priv = priv;
return p;
malloc_error:
calloc_error:
free( p );
free( priv );
return NULL;
@ -65,9 +64,11 @@ void path_free( path_t* p )
privcurve_free_members( &p->priv->curve );
privcurve_free_members( &p->priv->ocurve );
}
free( p->priv );
/* do not free p->fcurve ! */
}
free( p );
}
@ -94,15 +95,15 @@ int privcurve_init( privcurve_t* curve, int n )
{
memset( curve, 0, sizeof(privcurve_t) );
curve->n = n;
SAFE_MALLOC( curve->tag, n, int );
SAFE_MALLOC( curve->c, n, dpoint3_t );
SAFE_MALLOC( curve->vertex, n, dpoint_t );
SAFE_MALLOC( curve->alpha, n, double );
SAFE_MALLOC( curve->alpha0, n, double );
SAFE_MALLOC( curve->beta, n, double );
SAFE_CALLOC( curve->tag, n, int );
SAFE_CALLOC( curve->c, n, dpoint3_t );
SAFE_CALLOC( curve->vertex, n, dpoint_t );
SAFE_CALLOC( curve->alpha, n, double );
SAFE_CALLOC( curve->alpha0, n, double );
SAFE_CALLOC( curve->beta, n, double );
return 0;
malloc_error:
calloc_error:
free( curve->tag );
free( curve->c );
free( curve->vertex );

View File

@ -1,11 +1,11 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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 CURVE_H
#define CURVE_H
#include <auxiliary.h>
#include "auxiliary.h"
/* vertex is c[1] for tag=POTRACE_CORNER, and the intersection of
* .c[-1][2]..c[0] and c[1]..c[2] for tag=POTRACE_CURVETO. alpha is only
@ -21,7 +21,6 @@ struct privcurve_s
int* tag; /* tag[n]: POTRACE_CORNER or POTRACE_CURVETO */
dpoint_t( *c )[3]; /* c[n][i]: control points.
* c[n][0] is unused for tag[n]=POTRACE_CORNER */
/* the remainder of this structure is special to privcurve, and is
* used in EPS debug output and special EPS "short coding". These
* fields are valid only if "alphacurve" is set. */

View File

@ -1,21 +1,50 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: decompose.c 146 2007-04-09 00:43:46Z selinger $ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <potracelib.h>
#include <curve.h>
#include <lists.h>
#include <auxiliary.h>
#include <bitmap.h>
#include <decompose.h>
#include <progress.h>
#include "potracelib.h"
#include "curve.h"
#include "lists.h"
#include "bitmap.h"
#include "decompose.h"
#include "progress.h"
/* ---------------------------------------------------------------------- */
/* deterministically and efficiently hash (x,y) into a pseudo-random bit */
static inline int detrand( int x, int y )
{
unsigned int z;
static const unsigned char t[256] =
{
/* 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,
};
/* 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];
return z;
}
/* ---------------------------------------------------------------------- */
/* auxiliary bitmap manipulations */
@ -29,6 +58,7 @@ static void bm_clearexcess( potrace_bitmap_t* bm )
if( bm->w % BM_WORDBITS != 0 )
{
mask = BM_ALLBITS << ( BM_WORDBITS - (bm->w % BM_WORDBITS) );
for( y = 0; y<bm->h; y++ )
{
*bm_index( bm, bm->w, y ) &= mask;
@ -64,35 +94,6 @@ static void clear_bm_with_bbox( potrace_bitmap_t* bm, bbox_t* bbox )
/* ---------------------------------------------------------------------- */
/* auxiliary functions */
/* deterministically and efficiently hash (x,y) into a pseudo-random bit */
static inline int detrand( int x, int y )
{
unsigned int z;
static const unsigned char t[256] =
{
/* 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,
};
/* 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];
return z & 1;
}
/* return the "majority" value of bitmap bm at intersection (x,y). We
* assume that the bitmap is balanced at "radius" 1. */
static int majority( potrace_bitmap_t* bm, int x, int y )
@ -102,6 +103,7 @@ static int majority( potrace_bitmap_t* bm, int x, int y )
for( i = 2; i<5; i++ ) /* check at "radius" i */
{
ct = 0;
for( a = -i + 1; a<=i - 1; a++ )
{
ct += BM_GET( bm, x + a, y + i - 1 ) ? 1 : -1;
@ -179,6 +181,7 @@ static void xor_path( potrace_bitmap_t* bm, path_t* p )
y1 = p->priv->pt[p->priv->len - 1].y;
xa = p->priv->pt[0].x & - BM_WORDBITS;
for( k = 0; k<p->priv->len; k++ )
{
x = p->priv->pt[k].x;
@ -215,14 +218,17 @@ static void setbbox_path( bbox_t* bbox, path_t* p )
{
bbox->x0 = x;
}
if( x > bbox->x1 )
{
bbox->x1 = x;
}
if( y < bbox->y0 )
{
bbox->y0 = y;
}
if( y > bbox->y1 )
{
bbox->y1 = y;
@ -261,12 +267,15 @@ static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int tur
size += 100;
size = (int) (1.3 * size);
pt1 = (point_t*) realloc( pt, size * sizeof(point_t) );
if( !pt1 )
{
goto error;
}
pt = pt1;
}
pt[len].x = x;
pt[len].y = y;
len++;
@ -322,6 +331,7 @@ static path_t* findpath( potrace_bitmap_t* bm, int x0, int y0, int sign, int tur
/* allocate new path object */
p = path_new();
if( !p )
{
goto error;
@ -362,7 +372,8 @@ static void pathlist_to_tree( path_t* plist, potrace_bitmap_t* bm )
path_t* heap, * heap1;
path_t* cur;
path_t* head;
path_t** hook, ** hook_in, ** hook_out; /* for fast appending to linked list */
path_t** plist_hook; /* for fast appending to linked list */
path_t** hook_in, ** hook_out; /* for fast appending to linked list */
bbox_t bbox;
bm_clear( bm, 0 );
@ -411,6 +422,7 @@ static void pathlist_to_tree( path_t* plist, potrace_bitmap_t* bm )
*hook_out = cur;
break;
}
if( BM_GET( bm, p->priv->pt[0].x, p->priv->pt[0].y - 1 ) )
{
list_insert_beforehook( p, hook_in );
@ -431,6 +443,7 @@ static void pathlist_to_tree( path_t* plist, potrace_bitmap_t* bm )
head->next->childlist = heap;
heap = head->next;
}
if( head->childlist )
{
head->childlist->childlist = heap;
@ -440,6 +453,7 @@ static void pathlist_to_tree( path_t* plist, potrace_bitmap_t* bm )
/* copy sibling structure from "next" to "sibling" component */
p = plist;
while( p )
{
p1 = p->sibling;
@ -453,26 +467,31 @@ static void pathlist_to_tree( path_t* plist, potrace_bitmap_t* bm )
* contains a list of childlists which still need to be
* processed. */
heap = plist;
if( heap )
{
heap->next = NULL; /* heap is a linked list of childlists */
}
plist = NULL;
hook = &plist;
plist_hook = &plist;
while( heap )
{
heap1 = heap->next;
for( p = heap; p; p = p->sibling )
{
/* p is a positive path */
/* append to linked list */
list_insert_beforehook( p, hook );
list_insert_beforehook( p, plist_hook );
/* go through its children */
for( p1 = p->childlist; p1; p1 = p1->sibling )
{
/* append to linked list */
list_insert_beforehook( p1, hook );
list_insert_beforehook( p1, plist_hook );
/* append its childlist to heap, if non-empty */
if( p1->childlist )
{
@ -483,8 +502,6 @@ static void pathlist_to_tree( path_t* plist, potrace_bitmap_t* bm )
heap = heap1;
}
return;
}
@ -497,10 +514,13 @@ static int findnext( potrace_bitmap_t* bm, int* xp, int* yp )
{
int x;
int y;
int x0;
x0 = (*xp) & ~(BM_WORDBITS - 1);
for( y = *yp; y>=0; y-- )
{
for( x = 0; x<bm->w; x += BM_WORDBITS )
for( x = x0; x<bm->w; x += BM_WORDBITS )
{
if( *bm_index( bm, x, y ) )
{
@ -515,6 +535,8 @@ static int findnext( potrace_bitmap_t* bm, int* xp, int* yp )
return 0;
}
}
x0 = 0;
}
/* not found */
@ -536,11 +558,12 @@ int bm_to_pathlist( const potrace_bitmap_t* bm,
int y;
path_t* p;
path_t* plist = NULL; /* linked list of path objects */
path_t** hook = &plist; /* used to speed up appending to linked list */
path_t** plist_hook = &plist; /* used to speed up appending to linked list */
potrace_bitmap_t* bm1 = NULL;
int sign;
bm1 = bm_dup( bm );
if( !bm1 )
{
goto error;
@ -551,7 +574,9 @@ int bm_to_pathlist( const potrace_bitmap_t* bm,
bm_clearexcess( bm1 );
/* iterate through components */
x = 0;
y = bm1->h - 1;
while( findnext( bm1, &x, &y ) == 0 )
{
/* calculate the sign by looking at the original */
@ -559,6 +584,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 )
{
goto error;
@ -574,7 +600,7 @@ int bm_to_pathlist( const potrace_bitmap_t* bm,
}
else
{
list_insert_beforehook( p, hook );
list_insert_beforehook( p, plist_hook );
}
if( bm1->h > 0 ) /* to be sure */

View File

@ -1,14 +1,14 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: decompose.h 147 2007-04-09 00:44:09Z selinger $ */
#ifndef DECOMPOSE_H
#define DECOMPOSE_H
#include <potracelib.h>
#include <progress.h>
#include "potracelib.h"
#include "progress.h"
#include "curve.h"
int bm_to_pathlist( const potrace_bitmap_t* bm,
path_t** plistp,

View File

@ -1,18 +1,18 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: greymap.c 147 2007-04-09 00:44:09Z selinger $ */
/* Routines for manipulating greymaps, including reading pgm files. We
* only deal with greymaps of depth 8 bits. */
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <cmath>
#include <math.h>
#include <errno.h>
#include <greymap.h>
#include "greymap.h"
#include "bitops.h"
#define INTBITS ( 8 * sizeof(int) )
@ -24,28 +24,37 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp );
/* ---------------------------------------------------------------------- */
/* basic greymap routines */
/* return new un-initialized greymap. NULL with errno on error */
/* return new un-initialized greymap. NULL with errno on error.
* Assumes w, h >= 0. */
greymap_t* gm_new( int w, int h )
{
greymap_t* gm;
int errno_save;
ssize_t size = (ssize_t) w * (ssize_t) h * (ssize_t) sizeof(signed short int);
/* check for overflow error */
if( size < 0 || size / w / h != sizeof(signed short int) )
{
errno = ENOMEM;
return NULL;
}
gm = (greymap_t*) malloc( sizeof(greymap_t) );
if( !gm )
{
return NULL;
}
gm->w = w;
gm->h = h;
gm->map = (signed short int*) malloc( w * h * sizeof(signed short int) );
gm->map = (signed short int*) malloc( size );
if( !gm->map )
{
errno_save = errno;
free( gm );
errno = errno_save;
return NULL;
}
return gm;
}
@ -57,6 +66,7 @@ void gm_free( greymap_t* gm )
{
free( gm->map );
}
free( gm );
}
@ -70,7 +80,8 @@ greymap_t* gm_dup( greymap_t* gm )
{
return NULL;
}
memcpy( gm1->map, gm->map, gm->w * gm->h * 2 );
memcpy( gm1->map, gm->map, gm->w * gm->h * sizeof(signed short int) );
return gm1;
}
@ -82,7 +93,7 @@ void gm_clear( greymap_t* gm, int b )
if( b==0 )
{
memset( gm->map, 0, gm->w * gm->h * 2 );
memset( gm->map, 0, gm->w * gm->h * sizeof(signed short int) );
}
else
{
@ -106,17 +117,20 @@ static int fgetc_ws( FILE* f )
while( 1 )
{
c = fgetc( f );
if( c=='#' )
{
while( 1 )
{
c = fgetc( f );
if( c=='\n' || c==EOF )
{
break;
}
}
}
/* space, tab, line feed, carriage return, form-feed */
if( c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12 )
{
@ -140,10 +154,12 @@ static int readnum( FILE* f )
while( 1 )
{
c = fgetc_ws( f );
if( c==EOF )
{
return -1;
}
if( c>='0' && c<='9' )
{
break;
@ -152,18 +168,22 @@ static int readnum( FILE* f )
/* first digit is already in c */
acc = c - '0';
while( 1 )
{
c = fgetc( f );
if( c==EOF )
{
break;
}
if( c<'0' || c>'9' )
{
ungetc( c, f );
break;
}
acc *= 10;
acc += c - '0';
}
@ -183,10 +203,12 @@ static int readbit( FILE* f )
while( 1 )
{
c = fgetc_ws( f );
if( c==EOF )
{
return -1;
}
if( c>='0' && c<='1' )
{
break;
@ -219,20 +241,25 @@ int gm_read( FILE* f, greymap_t** gmp )
* by the PNM standard, but there is no harm in being lenient. */
magic[0] = fgetc_ws( f );
if( magic[0] == EOF )
{
/* files which contain only comments and whitespace count as "empty" */
return -3;
}
magic[1] = fgetc( f );
if( magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6' )
{
return gm_readbody_pnm( f, gmp, magic[1] );
}
if( magic[0] == 'B' && magic[1] == 'M' )
{
return gm_readbody_bmp( f, gmp );
}
return -4;
}
@ -251,12 +278,14 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
gm = NULL;
w = readnum( f );
if( w<0 )
{
goto format_error;
}
h = readnum( f );
if( h<0 )
{
goto format_error;
@ -264,6 +293,7 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
/* allocate greymap */
gm = gm_new( w, h );
if( !gm )
{
return -1;
@ -286,10 +316,12 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
for( x = 0; x<w; x++ )
{
b = readbit( f );
if( b<0 )
{
goto eof;
}
GM_UPUT( gm, x, y, b ? 0 : 255 );
}
}
@ -300,6 +332,7 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
/* read P2 format: PGM ascii */
max = readnum( f );
if( max<1 )
{
goto format_error;
@ -310,10 +343,12 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
for( x = 0; x<w; x++ )
{
b = readnum( f );
if( b<0 )
{
goto eof;
}
GM_UPUT( gm, x, y, b * 255 / max );
}
}
@ -324,6 +359,7 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
/* read P3 format: PPM ascii */
max = readnum( f );
if( max<1 )
{
goto format_error;
@ -334,13 +370,16 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
for( x = 0; x<w; x++ )
{
sum = 0;
for( i = 0; i<3; i++ )
{
b = readnum( f );
if( b<0 )
{
goto eof;
}
sum += b;
}
@ -354,6 +393,7 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
/* read P4 format: PBM raw */
b = fgetc( f ); /* read single white-space character after height */
if( b==EOF )
{
goto format_error;
@ -366,13 +406,15 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
for( i = 0; i<bpr; i++ )
{
b = fgetc( f );
if( b==EOF )
{
goto eof;
}
for( j = 0; j<8; j++ )
{
GM_PUT( gm, i * 8 + j, y, b & (0x80 >> j) ? 0 : 255 );
GM_PUT( gm, i * 8 + j, y, (b & (0x80 >> j)) ? 0 : 255 );
}
}
}
@ -383,12 +425,14 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
/* read P5 format: PGM raw */
max = readnum( f );
if( max<1 )
{
goto format_error;
}
b = fgetc( f ); /* read single white-space character after max */
if( b==EOF )
{
goto format_error;
@ -399,16 +443,21 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
for( x = 0; x<w; x++ )
{
b = fgetc( f );
if( b==EOF )
goto eof;
if( max>=256 )
{
b <<= 8;
b1 = fgetc( f );
if( b1==EOF )
goto eof;
b |= b1;
}
GM_UPUT( gm, x, y, b * 255 / max );
}
}
@ -419,12 +468,14 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
/* read P6 format: PPM raw */
max = readnum( f );
if( max<1 )
{
goto format_error;
}
b = fgetc( f ); /* read single white-space character after max */
if( b==EOF )
{
goto format_error;
@ -435,21 +486,27 @@ static int gm_readbody_pnm( FILE* f, greymap_t** gmp, int magic )
for( x = 0; x<w; x++ )
{
sum = 0;
for( i = 0; i<3; i++ )
{
b = fgetc( f );
if( b==EOF )
{
goto eof;
}
if( max>=256 )
{
b <<= 8;
b1 = fgetc( f );
if( b1==EOF )
goto eof;
b |= b1;
}
sum += b;
}
@ -469,6 +526,7 @@ eof:
format_error:
gm_free( gm );
if( magic == '1' || magic == '4' )
{
gm_read_error = "invalid pbm file";
@ -481,6 +539,7 @@ format_error:
{
gm_read_error = "invalid ppm file";
}
return -2;
}
@ -504,7 +563,12 @@ struct bmp_info_s
unsigned int YpixelsPerM;
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? */
};
typedef struct bmp_info_s bmp_info_t;
@ -524,10 +588,12 @@ static int bmp_readint( FILE* f, int n, unsigned int* p )
for( i = 0; i<n; i++ )
{
b = fgetc( f );
if( b==EOF )
{
return 1;
}
sum += b << (8 * i);
}
@ -552,9 +618,11 @@ static int bmp_pad( FILE* f )
int c, i, b;
c = (-bmp_count) & 3;
for( i = 0; i<c; i++ )
{
b = fgetc( f );
if( b==EOF )
{
return 1;
@ -575,10 +643,12 @@ static int bmp_forward( FILE* f, int pos )
while( bmp_pos < pos )
{
b = fgetc( f );
if( b==EOF )
{
return 1;
}
bmp_pos++;
bmp_count++;
}
@ -592,6 +662,9 @@ static int bmp_forward( FILE* f, int pos )
#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)
/* read BMP stream after magic number. Return values as for gm_read.
* We choose to be as permissive as possible, since there are many
* programs out there which produce BMP. For instance, ppmtobmp can
@ -610,6 +683,7 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
int col[2];
unsigned int bitbuf;
unsigned int n;
unsigned int redshift, greenshift, blueshift;
gm_read_error = NULL;
gm = NULL;
@ -624,7 +698,9 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
/* info header */
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 == 124 )
{
/* Windows or new OS/2 format */
bmpinfo.ctbits = 32; /* sample size in color table */
@ -638,6 +714,34 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
TRY( bmp_readint( f, 4, &bmpinfo.YpixelsPerM ) );
TRY( bmp_readint( f, 4, &bmpinfo.ncolors ) );
TRY( bmp_readint( f, 4, &bmpinfo.ColorsImportant ) );
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 ) );
TRY( bmp_readint( f, 4, &bmpinfo.AlphaMask ) );
}
if( bmpinfo.w > 0x7fffffff )
{
goto format_error;
}
if( bmpinfo.h > 0x7fffffff )
{
bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
bmpinfo.topdown = 1;
}
else
{
bmpinfo.topdown = 0;
}
if( bmpinfo.h > 0x7fffffff )
{
goto format_error;
}
}
else if( bmpinfo.InfoSize == 12 )
{
@ -649,13 +753,20 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
TRY( bmp_readint( f, 2, &bmpinfo.bits ) );
bmpinfo.comp = 0;
bmpinfo.ncolors = 0;
bmpinfo.topdown = 0;
}
else
{
goto format_error;
}
/* forward to color table (i.e., if bmpinfo.InfoSize == 64) */
if( bmpinfo.comp == 3 && bmpinfo.InfoSize < 108 )
{
/* bitfield feature is only understood with V4 and V5 format */
goto format_error;
}
/* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
TRY( bmp_forward( f, 14 + bmpinfo.InfoSize ) );
if( bmpinfo.Planes != 1 )
@ -672,7 +783,8 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
/* color table, present only if bmpinfo.bits <= 8. */
if( bmpinfo.bits <= 8 )
{
coltable = (int*) malloc( bmpinfo.ncolors * sizeof(int) );
coltable = (int*) calloc( bmpinfo.ncolors, sizeof(int) );
if( !coltable )
{
goto std_error;
@ -696,6 +808,7 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
/* allocate greymap */
gm = gm_new( bmpinfo.w, bmpinfo.h );
if( !gm )
{
goto std_error;
@ -716,12 +829,15 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
for( y = 0; y<bmpinfo.h; y++ )
{
bmp_pad_reset();
for( i = 0; 8 * i<bmpinfo.w; i++ )
{
TRY_EOF( bmp_readint( f, 1, &b ) );
for( j = 0; j<8; j++ )
{
GM_PUT( gm, i * 8 + j, y, b & (0x80 >> j) ? coltable[1] : coltable[0] );
GM_PUT( gm, i * 8 + j, ycorr( y ),
(b & (0x80 >> j)) ? coltable[1] : coltable[0] );
}
}
@ -737,11 +853,13 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
case 0x006:
case 0x007:
case 0x008:
for( y = 0; y<bmpinfo.h; y++ )
{
bmp_pad_reset();
bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */
n = 0; /* number of bits currently in bitbuffer */
for( x = 0; x<bmpinfo.w; x++ )
{
if( n < bmpinfo.bits )
@ -750,10 +868,11 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
bitbuf |= b << (INTBITS - 8 - n);
n += 8;
}
b = bitbuf >> (INTBITS - bmpinfo.bits);
bitbuf <<= bmpinfo.bits;
n -= bmpinfo.bits;
GM_UPUT( gm, x, y, coltable[b] );
GM_UPUT( gm, x, ycorr( y ), coltable[b] );
}
TRY( bmp_pad( f ) );
@ -762,7 +881,6 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
break;
case 0x010: /* 16-bit encoding */
/* can't do this format because it is not well-documented and I
* don't have any samples */
gm_read_error = "cannot handle bmp 16-bit coding";
@ -771,14 +889,39 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
case 0x018: /* 24-bit encoding */
case 0x020: /* 32-bit encoding */
for( y = 0; y<bmpinfo.h; y++ )
{
bmp_pad_reset();
for( x = 0; x<bmpinfo.w; x++ )
{
TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
c = ( (c >> 16) & 0xff ) + ( (c >> 8) & 0xff ) + (c & 0xff);
GM_UPUT( gm, x, y, c / 3 );
GM_UPUT( gm, x, ycorr( y ), c / 3 );
}
TRY( bmp_pad( f ) );
}
break;
case 0x320: /* 32-bit encoding with bitfields */
redshift = lobit( bmpinfo.RedMask );
greenshift = lobit( bmpinfo.GreenMask );
blueshift = lobit( bmpinfo.BlueMask );
for( y = 0; y<bmpinfo.h; y++ )
{
bmp_pad_reset();
for( x = 0; x<bmpinfo.w; x++ )
{
TRY_EOF( bmp_readint( f, bmpinfo.bits / 8, &c ) );
c = ( (c & bmpinfo.RedMask) >> redshift ) +
( (c & bmpinfo.GreenMask) >> greenshift ) +
( (c & bmpinfo.BlueMask) >> blueshift );
GM_UPUT( gm, x, ycorr( y ), c / 3 );
}
TRY( bmp_pad( f ) );
@ -789,15 +932,18 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
case 0x204: /* 4-bit runlength compressed encoding (RLE4) */
x = 0;
y = 0;
while( 1 )
{
TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */
TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
if( b>0 )
{
/* repeat count */
col[0] = coltable[(c >> 4) & 0xf];
col[1] = coltable[c & 0xf];
for( i = 0; i<b && x<bmpinfo.w; i++ )
{
if( x>=bmpinfo.w )
@ -805,11 +951,13 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
GM_UPUT( gm, x, y, col[i & 1] );
GM_UPUT( gm, x, ycorr( y ), col[i & 1] );
x++;
}
}
@ -841,16 +989,19 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
{
TRY_EOF( bmp_readint( f, 1, &b ) );
}
if( x>=bmpinfo.w )
{
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
GM_PUT( gm, x, y, coltable[( b >> ( 4 - 4 * (i & 1) ) ) & 0xf] );
GM_PUT( gm, x, ycorr( y ), coltable[( b >> ( 4 - 4 * (i & 1) ) ) & 0xf] );
x++;
}
@ -867,10 +1018,12 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
case 0x108: /* 8-bit runlength compressed encoding (RLE8) */
x = 0;
y = 0;
while( 1 )
{
TRY_EOF( bmp_readint( f, 1, &b ) ); /* opcode */
TRY_EOF( bmp_readint( f, 1, &c ) ); /* argument */
if( b>0 )
{
/* repeat count */
@ -881,11 +1034,13 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
GM_UPUT( gm, x, y, coltable[c] );
GM_UPUT( gm, x, ycorr( y ), coltable[c] );
x++;
}
}
@ -914,16 +1069,19 @@ static int gm_readbody_bmp( FILE* f, greymap_t** gmp )
for( i = 0; i<c; i++ )
{
TRY_EOF( bmp_readint( f, 1, &b ) );
if( x>=bmpinfo.w )
{
x = 0;
y++;
}
if( y>=bmpinfo.h )
{
break;
}
GM_PUT( gm, x, y, coltable[b] );
GM_PUT( gm, x, ycorr( y ), coltable[b] );
x++;
}
@ -955,10 +1113,12 @@ format_error:
try_error:
free( coltable );
free( gm );
if( !gm_read_error )
{
gm_read_error = "invalid bmp file";
}
return -2;
std_error:
@ -985,6 +1145,7 @@ int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, doubl
if( gamma != 1.0 )
{
gammatable[0] = 0;
for( v = 1; v<256; v++ )
{
gammatable[v] = (int) (255 * exp( log( v / 255.0 ) / gamma ) + 0.5);
@ -999,22 +1160,27 @@ int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, doubl
}
fprintf( f, raw ? "P5\n" : "P2\n" );
if( comment && *comment )
{
fprintf( f, "# %s\n", comment );
}
fprintf( f, "%d %d 255\n", gm->w, gm->h );
for( y = gm->h - 1; y>=0; y-- )
{
for( x = 0; x<gm->w; x++ )
{
v = GM_UGET( gm, x, y );
if( mode == GM_MODE_NONZERO )
{
if( v > 255 )
{
v = 510 - v;
}
if( v < 0 )
{
v = 0;
@ -1023,6 +1189,7 @@ int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, doubl
else if( mode == GM_MODE_ODD )
{
v = mod( v, 510 );
if( v > 255 )
{
v = 510 - v;
@ -1042,6 +1209,7 @@ int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, doubl
else if( mode == GM_MODE_NEGATIVE )
{
v = 510 - v;
if( v < 0 )
{
v = 0;
@ -1051,6 +1219,7 @@ int gm_writepgm( FILE* f, greymap_t* gm, char* comment, int raw, int mode, doubl
v = 255;
}
}
v = gammatable[v];
if( raw )
@ -1088,6 +1257,7 @@ int gm_print( FILE* f, greymap_t* gm )
{
d = 0;
t = 0;
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++ )
@ -1097,7 +1267,6 @@ int gm_print( FILE* f, greymap_t* gm )
}
}
if( t )
fputc( "*#=- "[5 * d / t], f ); /* what a cute trick :) */
}

View File

@ -1,19 +1,20 @@
/* Copyright (C) 2001-2007 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. */
/* Copyright (C) 2001-2015 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. */
/* $Id: greymap.h 147 2007-04-09 00:44:09Z selinger $ */
#ifndef PGM_H
#define PGM_H
#ifndef GREYMAP_H
#define GREYMAP_H
#include <stdio.h>
#include <stdlib.h>
/* 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. */
* ordered from bottom to top. The pixels in each row are given from
* left to right. */
struct greymap_s {
struct greymap_s
{
int w; /* width, in pixels */
int h; /* height, in pixels */
signed short int* map; /* raw data, w*h values */
@ -21,10 +22,12 @@ struct greymap_s {
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. */
* in the *lower* left corner. U* macros omit the bounds check. */
#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(gm)->w])
#define gm_safe(gm, x, y) ((int)(x)>=0 && (int)(x)<(gm)->w && (int)(y)>=0 && (int)(y)<(gm)->h)
#define gm_index( gm, x, y ) (&(gm)->map[(x) + (y) * (ssize_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_UGET( gm, x, y ) ( *gm_index( gm, x, y ) )
#define GM_UINC( gm, x, y, b ) ( *gm_index( gm, x, y ) += (short int) (b) )
@ -37,9 +40,9 @@ typedef struct greymap_s greymap_t;
#define GM_BGET( gm, x, y ) 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
number is nonzero, odd, or positive, respectively. We assume that 0
winding number corresponds to white (255). */
* refer to winding numbers. I.e., make a pixel black if winding
* number is nonzero, odd, or positive, respectively. We assume that 0
* winding number corresponds to white (255). */
#define GM_MODE_NONZERO 1
#define GM_MODE_ODD 2
#define GM_MODE_POSITIVE 3
@ -55,4 +58,4 @@ 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 );
#endif /* PGM_H */
#endif /* GREYMAP_H */

View File

@ -1,8 +1,7 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: lists.h 147 2007-04-09 00:44:09Z selinger $ */
#ifndef _PS_LISTS_H
#define _PS_LISTS_H
@ -33,7 +32,8 @@
* trick, we'd have to omit the ";" in such cases. */
#define MACRO_BEGIN do {
#define MACRO_END } while( 0 )
#define MACRO_END } \
while( 0 )
/* ---------------------------------------------------------------------- */
/* macros for singly-linked lists */
@ -45,7 +45,8 @@
* c, or NULL if not found */
#define list_find( elt, list, c ) \
MACRO_BEGIN list_forall( elt, list ) if( c ) \
break;MACRO_END
break; \
MACRO_END
/* like forall, except also set hook for elt. */
#define list_forall2( elt, list, hook ) \
@ -54,7 +55,8 @@
/* same as list_find, except also set hook for elt. */
#define list_find2( elt, list, c, hook ) \
MACRO_BEGIN list_forall2( elt, list, hook ) if( c ) \
break;MACRO_END
break; \
MACRO_END
/* same, except only use hook. */
#define _list_forall_hook( list, hook ) \
@ -63,7 +65,8 @@
/* same, except only use hook. Note: c may only refer to *hook, not elt. */
#define _list_find_hook( list, c, hook ) \
MACRO_BEGIN _list_forall_hook( list, hook ) if( c ) \
break;MACRO_END
break; \
MACRO_END
/* insert element after hook */
#define list_insert_athook( elt, hook ) \
@ -122,8 +125,8 @@
#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 ) {} \
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 */
@ -226,7 +229,8 @@
_hook1 = &( (*_hook1)->next1 ); \
*_hook1 = _elt; \
} \
} while( _hook1 != &(list) ); \
} \
while( _hook1 != &(list) ); \
MACRO_END
/* merge two sorted lists. Store result at &result */
@ -238,14 +242,17 @@
if( a==NULL ) { \
*_hook = b; \
break; \
} else if( b==NULL ) { \
} \
else if( b==NULL ) { \
*_hook = a; \
break; \
} else if( cond ) { \
} \
else if( cond ) { \
*_hook = a; \
_hook = &(a->next); \
a = a->next; \
} else { \
} \
else { \
*_hook = b; \
_hook = &(b->next); \
b = b->next; \
@ -262,7 +269,8 @@
elt->next = NULL; \
if( end ) { \
end->next = elt; \
} else { \
} \
else { \
head = elt; \
} \
end = elt; \
@ -282,7 +290,8 @@
head = head->next; \
if( head ) { \
head->prev = NULL; \
} else { \
} \
else { \
end = NULL; \
} \
elt->prev = NULL; \

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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,14 +8,21 @@
#define PLATFORM_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#include "config.h"
#endif
/* in Windows, set all file i/o to binary */
#ifdef __MINGW32__
#include <fcntl.h>
unsigned int _CRT_fmode = _O_BINARY;
#endif
static inline void platform_init( void )
{
_setmode( _fileno( stdin ), _O_BINARY );
_setmode( _fileno( stdout ), _O_BINARY );
}
#else
#ifdef __CYGWIN__
#include <fcntl.h>
@ -34,6 +41,7 @@ static inline void platform_init( void )
}
#endif
#endif
#endif /* PLATFORM_H */

View File

@ -1 +1 @@
#define POTRACELIB_VERSION "potracelib 1.8"
#define POTRACELIB_VERSION "potracelib 1.12"

View File

@ -1,20 +1,19 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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.
*/
* by the GNU General Public License. See the file COPYING for details. */
#include <stdlib.h>
#include <string.h>
#include <potracelib.h>
#include <curve.h>
#include <decompose.h>
#include <trace.h>
#include <progress.h>
#include "potracelib.h"
#include "curve.h"
#include "decompose.h"
#include "trace.h"
#include "progress.h"
#include <potrace_version.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#include "config.h"
#endif
/* default parameters */
@ -40,10 +39,12 @@ potrace_param_t* potrace_param_default( void )
potrace_param_t* p;
p = (potrace_param_t*) malloc( sizeof(potrace_param_t) );
if( !p )
{
return NULL;
}
memcpy( p, &param_default, sizeof(potrace_param_t) );
return p;
}
@ -52,8 +53,9 @@ potrace_param_t* potrace_param_default( void )
/* On success, returns a Potrace state st with st->status ==
* POTRACE_STATUS_OK. On failure, returns NULL if no Potrace state
* could be created (with errno set), or returns an incomplete Potrace
* state (with st->status == POTRACE_STATUS_INCOMPLETE). Complete or
* incomplete Potrace state can be freed with potrace_state_free(). */
* state (with st->status == POTRACE_STATUS_INCOMPLETE, and with errno
* set). Complete or incomplete Potrace state can be freed with
* potrace_state_free(). */
potrace_state_t* potrace_trace( const potrace_param_t* param, const potrace_bitmap_t* bm )
{
int r;
@ -72,6 +74,7 @@ potrace_state_t* potrace_trace( const potrace_param_t* param, const potrace_bitm
/* allocate state object */
st = (potrace_state_t*) malloc( sizeof(potrace_state_t) );
if( !st )
{
return NULL;
@ -81,6 +84,7 @@ potrace_state_t* potrace_trace( const potrace_param_t* param, const potrace_bitm
/* process the image */
r = bm_to_pathlist( bm, &plist, param, &subprog );
if( r )
{
free( st );
@ -97,6 +101,7 @@ potrace_state_t* potrace_trace( const potrace_param_t* param, const potrace_bitm
/* partial success. */
r = process_path( plist, param, &subprog );
if( r )
{
st->status = POTRACE_STATUS_INCOMPLETE;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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,7 +6,11 @@
#define POTRACELIB_H
/* this file defines the API for the core Potrace library. For a more
* detailed description of the API, see doc/potracelib.txt */
* detailed description of the API, see potracelib.pdf */
#ifdef __cplusplus
extern "C" {
#endif
/* ---------------------------------------------------------------------- */
/* tracing parameters */
@ -77,11 +81,10 @@ typedef struct potrace_dpoint_s potrace_dpoint_t;
/* closed curve segment */
struct potrace_curve_s
{
int n; // number of segments
int* tag; // tag[n]: POTRACE_CURVETO or POTRACE_CORNER
int n; /* number of segments */
int* tag; /* tag[n]: POTRACE_CURVETO or POTRACE_CORNER */
potrace_dpoint_t( *c )[3]; /* c[n][3]: control points.
* c[n][0] is unused for tag[n]=POTRACE_CORNER
*/
* c[n][0] is unused for tag[n]=POTRACE_CORNER */
};
typedef struct potrace_curve_s potrace_curve_t;
@ -136,4 +139,8 @@ void potrace_state_free( potrace_state_t* st );
* of potracelib */
const char* potrace_version( void );
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* POTRACELIB_H */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
@ -30,9 +30,10 @@ static inline void progress_update( double d, progress_t* prog )
{
double d_scaled;
if( prog->callback != NULL )
if( prog != NULL && prog->callback != NULL )
{
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 );
@ -52,7 +53,7 @@ static inline void progress_subrange_start( double a,
{
double min, max;
if( prog->callback == NULL )
if( prog == NULL || prog->callback == NULL )
{
sub->callback = NULL;
return;
@ -67,19 +68,19 @@ static inline void progress_subrange_start( double a,
sub->b = b;
return;
}
sub->callback = prog->callback;
sub->data = prog->data;
sub->epsilon = prog->epsilon;
sub->min = min;
sub->max = max;
sub->d_prev = prog->d_prev;
return;
}
static inline void progress_subrange_end( progress_t* prog, progress_t* sub )
{
if( prog->callback != NULL )
if( prog != NULL && prog->callback != NULL )
{
if( sub->callback == NULL )
{

View File

@ -1,17 +1,16 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: render.c 147 2007-04-09 00:44:09Z selinger $ */
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <math.h>
#include <string.h>
#include <render.h>
#include <greymap.h>
#include <auxiliary.h>
#include "render.h"
#include "greymap.h"
#include "auxiliary.h"
/* ---------------------------------------------------------------------- */
/* routines for anti-aliased rendering of curves */
@ -49,18 +48,22 @@ render_t* render_new( greymap_t* gm )
render_t* rm;
rm = (render_t*) malloc( sizeof(render_t) );
if( !rm )
{
return NULL;
}
memset( rm, 0, sizeof(render_t) );
rm->gm = gm;
rm->incrow_buf = (int*) malloc( gm->h * sizeof(int) );
rm->incrow_buf = (int*) calloc( gm->h, sizeof(int) );
if( !rm->incrow_buf )
{
free( rm );
return NULL;
}
memset( rm->incrow_buf, 0, gm->h * sizeof(int) );
return rm;
}
@ -82,6 +85,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 );
/* assert (rm->x0i != rm->x1i || rm->y0i != rm->y1i); */
@ -125,13 +129,16 @@ static void incrow( render_t* rm, int x, int y, int b )
{
x = rm->gm->w;
}
if( rm->incrow_buf[y] == 0 )
{
rm->incrow_buf[y] = x + 1; /* store x+1 so that we can use 0 for "vacant" */
return;
}
x0 = rm->incrow_buf[y] - 1;
rm->incrow_buf[y] = 0;
if( x0 < x )
{
for( i = x0; i<x; i++ )
@ -172,6 +179,7 @@ void render_lineto( render_t* rm, double x2, double y2 )
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);
@ -200,11 +208,12 @@ void render_lineto( render_t* rm, double x2, double y2 )
j++;
s = 0;
}
/* 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 )
@ -242,7 +251,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;
@ -254,12 +264,7 @@ void render_lineto( render_t* rm, double x2, double y2 )
/* render a Bezier curve. */
void render_curveto( render_t* rm,
double x2,
double y2,
double x3,
double y3,
double x4,
void render_curveto( render_t* rm, double x2, double y2, double x3, double y3, double x4,
double y4 )
{
double x1, y1, dd0, dd1, dd, delta, e2, epsilon, t;
@ -286,8 +291,8 @@ void render_curveto( render_t* rm,
{
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 ) );
y1 * cu( 1 - t ) + 3 * y2 * sq( 1 - t ) * t + 3 * y3 * (1 - t) * sq( t ) + y4 *
cu( t ) );
}
render_lineto( rm, x4, y4 );

View File

@ -1,13 +1,12 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: render.h 147 2007-04-09 00:44:09Z selinger $ */
#ifndef RENDER_H
#define RENDER_H
#include <greymap.h>
#include "greymap.h"
struct render_s
{

View File

@ -1,30 +1,29 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: trace.c 147 2007-04-09 00:44:09Z selinger $ */
/* transform jaggy paths into smooth curves */
#include <stdio.h>
#include <cmath>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <potracelib.h>
#include <curve.h>
#include <lists.h>
#include <auxiliary.h>
#include <trace.h>
#include <progress.h>
#include "potracelib.h"
#include "curve.h"
#include "lists.h"
#include "auxiliary.h"
#include "trace.h"
#include "progress.h"
#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 SAFE_MALLOC( var, n, typ ) \
if( ( var = (typ*) malloc( (n) * sizeof(typ) ) ) == NULL ) \
goto malloc_error
#define SAFE_CALLOC( var, n, typ ) \
if( ( var = (typ*) calloc( n, sizeof(typ) ) ) == NULL ) \
goto calloc_error
/* ---------------------------------------------------------------------- */
/* auxiliary functions */
@ -141,6 +140,7 @@ static void pointslope( privpath_t* pp, int i, int j, dpoint_t* ctr, dpoint_t* d
if( fabs( a ) >= fabs( c ) )
{
l = sqrt( a * a + b * b );
if( l!=0 )
{
dir->x = -b / l;
@ -150,12 +150,14 @@ static void pointslope( privpath_t* pp, int i, int j, dpoint_t* ctr, dpoint_t* d
else
{
l = sqrt( c * c + b * b );
if( l!=0 )
{
dir->x = -c / l;
dir->y = b / l;
}
}
if( l==0 )
{
dir->x = dir->y = 0; /* sometimes this can happen when k=4:
@ -269,11 +271,7 @@ static inline dpoint_t bezier( double t, dpoint_t p0, dpoint_t p1, dpoint_t p2,
/* calculate the point t in [0..1] on the (convex) bezier curve
* (p0,p1,p2,p3) which is tangent to q1-q0. Return -1.0 if there is no
* solution in [0..1]. */
static double tangent( dpoint_t p0,
dpoint_t p1,
dpoint_t p2,
dpoint_t p3,
dpoint_t q0,
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 */
@ -316,7 +314,6 @@ static double tangent( dpoint_t p0,
/* ---------------------------------------------------------------------- */
/* Preparation: fill in the sum* fields of a path (used for later
* rapid summing). Return 0 on success, 1 with errno set on
* failure. */
@ -325,7 +322,7 @@ static int calc_sums( privpath_t* pp )
int i, x, y;
int n = pp->len;
SAFE_MALLOC( pp->sums, pp->len + 1, sums_t );
SAFE_CALLOC( pp->sums, pp->len + 1, sums_t );
/* origin */
pp->x0 = pp->pt[0].x;
@ -333,6 +330,7 @@ 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; i<n; i++ )
{
x = pp->pt[i].x - pp->x0;
@ -346,13 +344,12 @@ static int calc_sums( privpath_t* pp )
return 0;
malloc_error:
calloc_error:
return 1;
}
/* ---------------------------------------------------------------------- */
/* Stage 1: determine the straight subpaths (Sec. 2.2.1). Fill in the
* "lon" component of a path object (based on pt/len). For each i,
* lon[i] is the furthest index such that a straight line can be drawn
@ -396,8 +393,8 @@ static int calc_lon( privpath_t* pp )
point_t dk; /* direction of k-k1 */
int a, b, c, d;
SAFE_MALLOC( pivk, n, int );
SAFE_MALLOC( nc, n, int );
SAFE_CALLOC( pivk, n, int );
SAFE_CALLOC( nc, n, int );
/* initialize the nc data structure. Point from each point to the
* furthest future point to which it is connected by a vertical or
@ -407,16 +404,18 @@ static int calc_lon( privpath_t* pp )
* in practice, correctness does not depend on the word "furthest"
* above. */
k = 0;
for( i = n - 1; i>=0; i-- )
{
if( pt[i].x != pt[k].x && pt[i].y != pt[k].y )
{
k = i + 1; /* necessarily i<n-1 in this case */
}
nc[i] = k;
}
SAFE_MALLOC( pp->lon, n, int );
SAFE_CALLOC( pp->lon, n, int );
/* determine pivot points: for each i, let pivk[i] be the furthest k
* such that all j with i<j<k lie on a line connecting i,k. */
@ -426,8 +425,7 @@ static int calc_lon( privpath_t* pp )
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,6 +436,7 @@ static int calc_lon( privpath_t* pp )
/* find the next k such that no straight line from i to k */
k = nc[i];
k1 = i;
while( 1 )
{
dir = ( 3 + 3 * sign( pt[k].x - pt[k1].x ) + sign( pt[k].y - pt[k1].y ) ) / 2;
@ -468,19 +467,24 @@ static int calc_lon( privpath_t* pp )
{
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 );
if( xprod( constraint[1], off ) <= 0 )
{
constraint[1] = off;
}
}
k1 = k;
k = nc[k1];
if( !cyclic( k, i, k1 ) )
{
break;
@ -488,7 +492,6 @@ static int calc_lon( privpath_t* pp )
}
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. */
@ -496,7 +499,6 @@ constraint_viol:
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. */
@ -504,18 +506,20 @@ constraint_viol:
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 )
{
j = floordiv( a, -b );
}
if( d>0 )
{
j = min( j, floordiv( -c, d ) );
}
pivk[i] = mod( k1 + j, n );
foundk:
;
@ -526,12 +530,14 @@ foundk:
j = pivk[n - 1];
pp->lon[n - 1] = j;
for( i = n - 2; i>=0; i-- )
{
if( cyclic( i + 1, pivk[i], j ) )
{
j = pivk[i];
}
pp->lon[i] = j;
}
@ -544,7 +550,7 @@ foundk:
free( nc );
return 0;
malloc_error:
calloc_error:
free( pivk );
free( nc );
return 1;
@ -574,15 +580,28 @@ static double penalty3( privpath_t* pp, int i, int j )
if( j>=n )
{
j -= n;
r += 1;
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;
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;
k = j + 1 - i + r * n;
/* 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;
x2 = sums[j + 1].x2 - sums[i].x2;
xy = sums[j + 1].xy - sums[i].xy;
y2 = sums[j + 1].y2 - sums[i].y2;
k = j + 1 - i;
}
else
{
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;
@ -601,7 +620,7 @@ static double penalty3( privpath_t* pp, int i, int j )
/* find the optimal polygon. Fill in the m and po components. Return 1
* on failure with errno set, else 0. Non-cyclic version: assumes i=0
* is in the polygon. Fixme: ### implement cyclic version. */
* is in the polygon. Fixme: implement cyclic version. */
static int bestpolygon( privpath_t* pp )
{
int i, j, m, k;
@ -616,21 +635,23 @@ static int bestpolygon( privpath_t* pp )
double best;
int c;
SAFE_MALLOC( pen, n + 1, double );
SAFE_MALLOC( prev, n + 1, int );
SAFE_MALLOC( clip0, n, int );
SAFE_MALLOC( clip1, n + 1, int );
SAFE_MALLOC( seg0, n + 1, int );
SAFE_MALLOC( seg1, n + 1, int );
SAFE_CALLOC( pen, n + 1, double );
SAFE_CALLOC( prev, n + 1, int );
SAFE_CALLOC( clip0, n, int );
SAFE_CALLOC( clip1, n + 1, int );
SAFE_CALLOC( seg0, n + 1, int );
SAFE_CALLOC( seg1, n + 1, int );
/* calculate clipped paths */
for( i = 0; i<n; i++ )
{
c = mod( pp->lon[mod( i - 1, n )] - 1, n );
if( c == i )
{
c = mod( i + 1, n );
}
if( c < i )
{
clip0[i] = n;
@ -644,6 +665,7 @@ static int bestpolygon( privpath_t* pp )
/* calculate backwards path clipping, non-cyclic. j <= clip0[i] iff
* clip1[j] <= i, for i,j=0..n. */
j = 1;
for( i = 0; i<n; i++ )
{
while( j <= clip0[i] )
@ -655,6 +677,7 @@ static int bestpolygon( privpath_t* pp )
/* calculate seg0[j] = longest path from 0 with j segments */
i = 0;
for( j = 0; i<n; j++ )
{
seg0[j] = i;
@ -666,6 +689,7 @@ static int bestpolygon( privpath_t* pp )
/* calculate seg1[j] = longest path to n with m-j segments */
i = n;
for( j = m; j>0; j-- )
{
seg1[j] = i;
@ -675,19 +699,21 @@ static int bestpolygon( privpath_t* pp )
seg1[0] = 0;
/* now find the shortest path with m segments, based on penalty3 */
/* note: the outer 2 loops jointly have at most n interations, thus
/* note: the outer 2 loops jointly have at most n iterations, thus
* the worst-case behavior here is quadratic. In practice, it is
* close to linear since the inner loop tends to be short. */
pen[0] = 0;
for( j = 1; j<=m; j++ )
{
for( i = seg1[j]; i<=seg0[j]; i++ )
{
best = -1;
for( k = seg0[j - 1]; k>=clip1[i]; k-- )
{
thispen = penalty3( pp, k, i ) + pen[k];
if( best < 0 || thispen < best )
{
prev[i] = k;
@ -700,7 +726,7 @@ static int bestpolygon( privpath_t* pp )
}
pp->m = m;
SAFE_MALLOC( pp->po, m, int );
SAFE_CALLOC( pp->po, m, int );
/* read off shortest path */
for( i = n, j = m - 1; i>0; j-- )
@ -717,7 +743,7 @@ static int bestpolygon( privpath_t* pp )
free( seg1 );
return 0;
malloc_error:
calloc_error:
free( pen );
free( prev );
free( clip0 );
@ -754,14 +780,15 @@ static int adjust_vertices( privpath_t* pp )
dpoint_t s;
int r;
SAFE_MALLOC( ctr, m, dpoint_t );
SAFE_MALLOC( dir, m, dpoint_t );
SAFE_MALLOC( q, m, quadform_t );
SAFE_CALLOC( ctr, m, dpoint_t );
SAFE_CALLOC( dir, m, dpoint_t );
SAFE_CALLOC( q, m, quadform_t );
r = privcurve_init( &pp->curve, m );
if( r )
{
goto malloc_error;
goto calloc_error;
}
/* calculate "optimal" point-slope representation for each line
@ -779,6 +806,7 @@ static int adjust_vertices( privpath_t* pp )
for( i = 0; i<m; i++ )
{
d = sq( dir[i].x ) + sq( dir[i].y );
if( d == 0.0 )
{
for( j = 0; j<3; j++ )
@ -794,6 +822,7 @@ static int adjust_vertices( privpath_t* pp )
v[0] = dir[i].y;
v[1] = -dir[i].x;
v[2] = -v[1] * ctr[i].y - v[0] * ctr[i].x;
for( l = 0; l<3; l++ )
{
for( k = 0; k<3; k++ )
@ -846,6 +875,7 @@ static int adjust_vertices( privpath_t* pp )
#endif
det = Q[0][0] * Q[1][1] - Q[0][1] * Q[1][0];
if( det != 0.0 )
{
w.x = (-Q[0][2] * Q[1][1] + Q[1][2] * Q[0][1]) / det;
@ -870,8 +900,10 @@ static int adjust_vertices( privpath_t* pp )
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( k = 0; k<3; k++ )
@ -883,6 +915,7 @@ static int adjust_vertices( privpath_t* pp )
dx = fabs( w.x - s.x );
dy = fabs( w.y - s.y );
if( dx <= .5 && dy <= .5 )
{
pp->curve.vertex[i].x = w.x + x0;
@ -900,12 +933,14 @@ static int adjust_vertices( privpath_t* pp )
{
goto fixx;
}
for( z = 0; z<2; z++ ) /* 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;
@ -915,16 +950,19 @@ static int adjust_vertices( privpath_t* pp )
}
fixx:
if( Q[1][1] == 0.0 )
{
goto corners;
}
for( z = 0; z<2; z++ ) /* 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;
@ -934,6 +972,7 @@ fixx:
}
corners:
/* check four corners */
for( l = 0; l<2; l++ )
{
@ -942,6 +981,7 @@ corners:
w.x = s.x - 0.5 + l;
w.y = s.y - 0.5 + k;
cand = quadform( Q, w );
if( cand < min )
{
min = cand;
@ -961,7 +1001,7 @@ corners:
free( q );
return 0;
malloc_error:
calloc_error:
free( ctr );
free( dir );
free( q );
@ -972,8 +1012,24 @@ malloc_error:
/* ---------------------------------------------------------------------- */
/* Stage 4: smoothing and corner analysis (Sec. 2.3.3) */
/* Always succeeds and returns 0 */
static int smooth( privcurve_t* curve, int sign, double alphamax )
/* reverse orientation of a path */
static void reverse( privcurve_t* curve )
{
int m = curve->n;
int i, j;
dpoint_t tmp;
for( i = 0, j = m - 1; i<j; i++, j-- )
{
tmp = curve->vertex[i];
curve->vertex[i] = curve->vertex[j];
curve->vertex[j] = tmp;
}
}
/* Always succeeds */
static void smooth( privcurve_t* curve, double alphamax )
{
int m = curve->n;
@ -981,18 +1037,6 @@ static int smooth( privcurve_t* curve, int sign, double alphamax )
double dd, denom, alpha;
dpoint_t p2, p3, p4;
if( sign == '-' )
{
/* reverse orientation of negative paths */
for( i = 0, j = m - 1; i<j; i++, j-- )
{
dpoint_t tmp;
tmp = curve->vertex[i];
curve->vertex[i] = curve->vertex[j];
curve->vertex[j] = tmp;
}
}
/* examine each vertex and find its best fit */
for( i = 0; i<m; i++ )
{
@ -1001,6 +1045,7 @@ static int smooth( privcurve_t* curve, int sign, double alphamax )
p4 = interval( 1 / 2.0, curve->vertex[k], curve->vertex[j] );
denom = ddenom( curve->vertex[i], curve->vertex[k] );
if( denom != 0.0 )
{
dd = dpara( curve->vertex[i], curve->vertex[j], curve->vertex[k] ) / denom;
@ -1012,9 +1057,10 @@ static int smooth( privcurve_t* curve, int sign, double alphamax )
{
alpha = 4 / 3.0;
}
curve->alpha0[j] = alpha; /* remember "original" value of alpha */
if( alpha > alphamax ) /* pointed corner */
if( alpha >= alphamax ) /* pointed corner */
{
curve->tag[j] = POTRACE_CORNER;
curve->c[j][1] = curve->vertex[j];
@ -1030,6 +1076,7 @@ static int smooth( privcurve_t* curve, int sign, double alphamax )
{
alpha = 1;
}
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;
@ -1037,13 +1084,12 @@ static int smooth( privcurve_t* curve, int sign, double alphamax )
curve->c[j][1] = p3;
curve->c[j][2] = p4;
}
curve->alpha[j] = alpha; /* store the "cropped" value of alpha */
curve->beta[j] = 0.5;
}
curve->alphacurve = 1;
return 0;
}
@ -1089,27 +1135,33 @@ static int opti_penalty( privpath_t* pp,
i1 = mod( i + 1, m );
k1 = mod( k + 1, m );
conv = convc[k1];
if( conv == 0 )
{
return 1;
}
d = ddist( pp->curve.vertex[i], pp->curve.vertex[i1] );
for( k = k1; k!=j; k = k1 )
{
k1 = mod( k + 1, m );
k2 = mod( k + 2, m );
if( convc[k1] != conv )
{
return 1;
}
if( sign( cprod( pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1],
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;
}
@ -1124,6 +1176,7 @@ static int opti_penalty( privpath_t* pp,
/* 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;
if( i>=j )
{
area += areac[m];
@ -1173,26 +1226,33 @@ static int opti_penalty( privpath_t* pp,
{
k1 = mod( k + 1, m );
t = tangent( p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1] );
if( t<-.5 )
{
return 1;
}
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 */
{
return 1;
}
d1 = dpara( pp->curve.vertex[k], pp->curve.vertex[k1], pt ) / d;
if( fabs( d1 ) > opttolerance )
{
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 )
{
return 1;
}
res->pen += sq( d1 );
}
@ -1201,28 +1261,35 @@ static int opti_penalty( privpath_t* pp,
{
k1 = mod( k + 1, m );
t = tangent( p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2] );
if( t<-.5 )
{
return 1;
}
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 */
{
return 1;
}
d1 = dpara( pp->curve.c[k][2], pp->curve.c[k1][2], pt ) / d;
d2 = dpara( pp->curve.c[k][2], pp->curve.c[k1][2], pp->curve.vertex[k1] ) / d;
d2 *= 0.75 * pp->curve.alpha[k1];
if( d2 < 0 )
{
d1 = -d1;
d2 = -d2;
}
if( d1 < d2 - opttolerance )
{
return 1;
}
if( d1 < d2 )
{
res->pen += sq( d1 - d2 );
@ -1238,14 +1305,14 @@ static int opti_penalty( privpath_t* pp,
* on failure. */
static int opticurve( privpath_t* pp, double opttolerance )
{
int seg_count = pp->curve.n; // segment count in pp->curve
int m = pp->curve.n;
int* pt = NULL; /* pt[m+1] */
double* pen = NULL; /* pen[m+1] */
int* len = NULL; /* len[m+1] */
opti_t* opt = NULL; /* opt[m+1] */
int om;
int j, r;
opti_t curve_prms;
int i, j, r;
opti_t o;
dpoint_t p0;
int i1;
double area;
@ -1256,22 +1323,21 @@ static int opticurve( privpath_t* pp, double opttolerance )
int* convc = NULL; /* conv[m]: pre-computed convexities */
double* areac = NULL; /* cumarea[m+1]: cache for fast area computation */
SAFE_MALLOC( pt, seg_count + 1, int );
SAFE_MALLOC( pen, seg_count + 1, double );
SAFE_MALLOC( len, seg_count + 1, int );
SAFE_MALLOC( opt, seg_count + 1, opti_t );
SAFE_MALLOC( convc, seg_count, int );
SAFE_MALLOC( areac, seg_count + 1, double );
SAFE_CALLOC( pt, m + 1, int );
SAFE_CALLOC( pen, m + 1, double );
SAFE_CALLOC( len, m + 1, int );
SAFE_CALLOC( opt, m + 1, opti_t );
SAFE_CALLOC( convc, m, int );
SAFE_CALLOC( areac, m + 1, double );
/* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
for( int i = 0; i<seg_count; i++ )
for( i = 0; i<m; i++ )
{
if( pp->curve.tag[i] == POTRACE_CURVETO )
{
convc[i] =
sign( dpara( pp->curve.vertex[mod( i - 1, seg_count )],
pp->curve.vertex[i],
pp->curve.vertex[mod( i + 1, seg_count )] ) );
sign( dpara( pp->curve.vertex[mod( i - 1, m )], pp->curve.vertex[i],
pp->curve.vertex[mod( i + 1, m )] ) );
}
else
{
@ -1283,9 +1349,11 @@ static int opticurve( privpath_t* pp, double opttolerance )
area = 0.0;
areac[0] = 0.0;
p0 = pp->curve.vertex[0];
for( int i = 0; i<seg_count; i++ )
for( i = 0; i<m; i++ )
{
i1 = mod( i + 1, seg_count );
i1 = mod( i + 1, m );
if( pp->curve.tag[i1] == POTRACE_CURVETO )
{
alpha = pp->curve.alpha[i1];
@ -1294,6 +1362,7 @@ static int opticurve( privpath_t* pp, double opttolerance )
pp->curve.c[i1][2] ) / 2;
area += dpara( p0, pp->curve.c[i][2], pp->curve.c[i1][2] ) / 2;
}
areac[i + 1] = area;
}
@ -1301,64 +1370,60 @@ static int opticurve( privpath_t* pp, double opttolerance )
pen[0] = 0;
len[0] = 0;
// Avoid not initialized value for opt[j] (should not occur, but...)
for( j = 0; j<=seg_count; j++ )
{
opt[j].pen = 0.0; // penalty
opt[j].c[0].x = opt[j].c[1].x = opt[j].c[0].y = opt[j].c[1].y = 0;
opt[j].t = opt[j].s = opt[j].alpha = 0.0; // curve parameters
}
/* Fixme: we always start from a fixed point -- should find the best
* curve cyclically ### */
* curve cyclically */
for( j = 1; j<=seg_count; j++ )
for( j = 1; j<=m; j++ )
{
/* calculate best path from 0 to j */
pt[j] = j - 1;
pen[j] = pen[j - 1];
len[j] = len[j - 1] + 1;
for( int i = j - 2; i>=0; i-- )
for( i = j - 2; i>=0; i-- )
{
r = opti_penalty( pp, i, mod( j, seg_count ), &curve_prms, opttolerance, convc, areac );
r = opti_penalty( pp, i, mod( j, m ), &o, opttolerance, convc, areac );
if( r )
{
break;
}
if( len[j] > len[i] + 1 || (len[j] == len[i] + 1 && pen[j] > pen[i] + curve_prms.pen) )
if( len[j] > len[i] + 1 || (len[j] == len[i] + 1 && pen[j] > pen[i] + o.pen) )
{
pt[j] = i;
pen[j] = pen[i] + curve_prms.pen;
pen[j] = pen[i] + o.pen;
len[j] = len[i] + 1;
opt[j] = curve_prms;
opt[j] = o;
}
}
}
om = len[seg_count];
om = len[m];
r = privcurve_init( &pp->ocurve, om );
if( r )
{
goto malloc_error;
goto calloc_error;
}
SAFE_MALLOC( s, om, double );
SAFE_MALLOC( t, om, double );
j = seg_count;
for( int i = om - 1; i>=0; i-- )
SAFE_CALLOC( s, om, double );
SAFE_CALLOC( t, om, double );
j = m;
for( i = om - 1; i>=0; i-- )
{
if( pt[j]==j - 1 )
{
pp->ocurve.tag[i] = pp->curve.tag[mod( j, seg_count )];
pp->ocurve.c[i][0] = pp->curve.c[mod( j, seg_count )][0];
pp->ocurve.c[i][1] = pp->curve.c[mod( j, seg_count )][1];
pp->ocurve.c[i][2] = pp->curve.c[mod( j, seg_count )][2];
pp->ocurve.vertex[i] = pp->curve.vertex[mod( j, seg_count )];
pp->ocurve.alpha[i] = pp->curve.alpha[mod( j, seg_count )];
pp->ocurve.alpha0[i] = pp->curve.alpha0[mod( j, seg_count )];
pp->ocurve.beta[i] = pp->curve.beta[mod( j, seg_count )];
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.beta[i] = pp->curve.beta[mod( j, m )];
s[i] = t[i] = 1.0;
}
else
@ -1366,19 +1431,21 @@ static int opticurve( privpath_t* pp, double opttolerance )
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, seg_count )][2];
pp->ocurve.vertex[i] = interval( opt[j].s, pp->curve.c[mod( j, seg_count )][2],
pp->curve.vertex[mod( j, seg_count )] );
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;
}
j = pt[j];
}
/* calculate beta parameters */
for( int i = 0; i<om; i++ )
for( i = 0; i<om; i++ )
{
i1 = mod( i + 1, om );
pp->ocurve.beta[i] = s[i] / (s[i] + t[i1]);
@ -1396,7 +1463,7 @@ static int opticurve( privpath_t* pp, double opttolerance )
free( areac );
return 0;
malloc_error:
calloc_error:
free( pt );
free( pen );
free( len );
@ -1436,7 +1503,14 @@ int process_path( path_t* plist, const potrace_param_t* param, progress_t* progr
TRY( calc_lon( p->priv ) );
TRY( bestpolygon( p->priv ) );
TRY( adjust_vertices( p->priv ) );
TRY( smooth( &p->priv->curve, p->sign, param->alphamax ) );
if( p->sign == '-' ) /* reverse orientation of negative paths */
{
reverse( &p->priv->curve );
}
smooth( &p->priv->curve, param->alphamax );
if( param->opticurve )
{
TRY( opticurve( p->priv, param->opttolerance ) );
@ -1446,6 +1520,7 @@ int process_path( path_t* plist, const potrace_param_t* param, progress_t* progr
{
p->priv->fcurve = &p->priv->curve;
}
privcurve_to_curve( p->priv->fcurve, &p->curve );
if( progress->callback )

View File

@ -1,14 +1,14 @@
/* Copyright (C) 2001-2007 Peter Selinger.
/* Copyright (C) 2001-2015 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. */
/* $Id: trace.h 147 2007-04-09 00:44:09Z selinger $ */
#ifndef TRACE_H
#define TRACE_H
#include <potracelib.h>
#include <progress.h>
#include "potracelib.h"
#include "progress.h"
#include "curve.h"
int process_path( path_t* plist, const potrace_param_t* param, progress_t* progress );