30#include <potracelib.h>
32#include <wx/translation.h>
41static double cube(
double x )
48static void BezierToPolyline( std::vector<potrace_dpoint_t>& aCornersBuffer, potrace_dpoint_t p1, potrace_dpoint_t p2,
49 potrace_dpoint_t p3, potrace_dpoint_t p4 )
64 dd0 =
square( p1.x - 2 * p2.x + p3.x ) +
square( p1.y - 2 * p2.y + p3.y );
65 dd1 =
square( p2.x - 2 * p3.x + p4.x ) +
square( p2.y - 2 * p3.y + p4.y );
66 dd = 6 * sqrt( std::max( dd0, dd1 ) );
72 potrace_dpoint_t intermediate_point;
73 intermediate_point.x = p1.x *
cube( 1 - t ) + 3 * p2.x *
square( 1 - t ) * t
74 + 3 * p3.x * ( 1 - t ) *
square( t ) + p4.x *
cube( t );
76 intermediate_point.y = p1.y *
cube( 1 - t ) + 3 * p2.y *
square( 1 - t ) * t
77 + 3 * p3.y * ( 1 - t ) *
square( t ) + p4.y *
cube( t );
79 aCornersBuffer.push_back( intermediate_point );
82 aCornersBuffer.push_back( p4 );
88 wxImage bilevel = aImage.ConvertToGreyscale();
95 const int pixelCount = bilevel.GetWidth() * bilevel.GetHeight();
96 const unsigned char*
source = aImage.GetData();
97 const unsigned char* alpha = bilevel.HasAlpha() ? bilevel.GetAlpha() :
nullptr;
98 unsigned char* grey = bilevel.GetData();
100 const bool hasMask = aImage.HasMask();
101 const unsigned char maskRed = hasMask ? aImage.GetMaskRed() : 0;
102 const unsigned char maskGreen = hasMask ? aImage.GetMaskGreen() : 0;
103 const unsigned char maskBlue = hasMask ? aImage.GetMaskBlue() : 0;
105 const unsigned char threshold = aThreshold * 255;
106 const unsigned char alphaThreshold = 0.7 * threshold;
110 for(
int ii = 0; ii < pixelCount; ii++ )
112 unsigned char level = grey[ii * 3];
115 if( hasMask &&
source[ii * 3] == maskRed &&
source[ii * 3 + 1] == maskGreen &&
source[ii * 3 + 2] == maskBlue )
123 level = ( level < threshold && ( !alpha || alpha[ii] > alphaThreshold ) ) ? 0 : 255;
125 grey[ii * 3] = level;
126 grey[ii * 3 + 1] = level;
127 grey[ii * 3 + 2] = level;
134wxImage
MakeBilevelPreview(
const wxImage& aImage,
double aThreshold,
bool aInvert,
const wxSize& aRoom )
138 if( !preview.IsOk() )
141 double fit = std::min( (
double) aRoom.x / preview.GetWidth(), (
double) aRoom.y / preview.GetHeight() );
145 preview = preview.Scale(
KiROUND( preview.GetWidth() * fit ),
KiROUND( preview.GetHeight() * fit ),
146 wxIMAGE_QUALITY_NORMAL );
157 potrace_bitmap_t* potraceBitmap = bm_new( aBilevelImage.GetWidth(), aBilevelImage.GetHeight() );
165 for(
int y = 0; y < aBilevelImage.GetHeight(); y++ )
167 for(
int x = 0; x < aBilevelImage.GetWidth(); x++ )
169 unsigned char pixel = aBilevelImage.GetGreen( x, y );
170 BM_PUT( potraceBitmap, x, y, pixel ? 0 : 1 );
174 potrace_param_t* param = potrace_param_default();
178 bm_free( potraceBitmap );
180 wxString::Format(
_(
"Error allocating parameters: %s" ), wxString::FromUTF8( strerror( errno ) ) ),
188 param->opttolerance = 0.2;
190 potrace_state_t* st = potrace_trace( param, potraceBitmap );
192 if( !st || st->status != POTRACE_STATUS_OK )
195 potrace_state_free( st );
197 potrace_param_free( param );
198 bm_free( potraceBitmap );
200 aReporter.
Report( wxString::Format(
_(
"Error tracing bitmap: %s" ), wxString::FromUTF8( strerror( errno ) ) ),
205 std::vector<potrace_dpoint_t> cornersBuffer;
208 bool mainOutline =
true;
209 int droppedGroups = 0;
213 int cnt =
path->curve.n;
214 int* tag =
path->curve.tag;
215 potrace_dpoint_t( *c )[3] =
path->curve.c;
216 potrace_dpoint_t startpoint = c[cnt - 1][2];
218 for(
int ii = 0; ii < cnt; ii++ )
223 cornersBuffer.push_back( c[ii][1] );
224 cornersBuffer.push_back( c[ii][2] );
225 startpoint = c[ii][2];
228 case POTRACE_CURVETO:
229 BezierToPolyline( cornersBuffer, startpoint, c[ii][0], c[ii][1], c[ii][2] );
230 startpoint = c[ii][2];
240 for(
const potrace_dpoint_s& pt : cornersBuffer )
243 cornersBuffer.clear();
246 if(
path->next ==
nullptr ||
path->next->sign ==
'+' )
273 potrace_state_free( st );
274 potrace_param_free( param );
275 bm_free( potraceBitmap );
279 if( droppedGroups > 0 )
281 aReporter.
Report( wxString::Format( wxPLURAL(
"%d region of the image could not be traced.",
282 "%d regions of the image could not be traced.", droppedGroups ),
wxImage ConvertImageToBilevel(const wxImage &aImage, double aThreshold, bool aInvert)
Reduce an image to pure black and white.
static void BezierToPolyline(std::vector< potrace_dpoint_t > &aCornersBuffer, potrace_dpoint_t p1, potrace_dpoint_t p2, potrace_dpoint_t p3, potrace_dpoint_t p4)
wxImage MakeBilevelPreview(const wxImage &aImage, double aThreshold, bool aInvert, const wxSize &aRoom)
Produce the black and white view of an image, shrunk to fit a preview area.
static double cube(double x)
static double square(double x)
SHAPE_POLY_SET TraceBilevelImage(const wxImage &aBilevelImage, double aScaleX, double aScaleY, REPORTER &aReporter)
Trace the black regions of a black and white image into filled polygons.
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Report a string with a given severity.
Represent a set of closed polygons.
void RemoveAllContours()
Remove all outlines & holes (clears) the polygon set.
int NormalizeAreaOutlines()
Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s).
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
wxString result
Test unit parsing edge cases and error handling.