Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

freetype: fix for huge CtoL param. #3585

Open
wants to merge 2 commits into
base: 4.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 75 additions & 22 deletions modules/freetype/src/freetype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,20 +723,45 @@ int FreeType2Impl::coFn( const FT_Vector *cnt,

PathUserData *p = (PathUserData *)user;

// Calicurate upper limit of CtoL.
// It is same as total length of polylines{ mOldP, cnt, to }.

const double dx1 = p->mOldP.x - cnt->x;
const double dy1 = p->mOldP.y - cnt->y;
const double dx2 = cnt->x - to->x;
const double dy2 = cnt->y - to->y;

const int maxL = static_cast<int>(
std::sqrt( dx1 * dx1 + dy1 * dy1 ) +
std::sqrt( dx2 * dx2 + dy2 * dy2 )
);

// iCtoL should be less than INT_MAX to avoid overflowing for int i.
// iCtoL should not be 0 to avoid dividing 0 for double u.
const int iCtoL = std::max( 1, std::min( { maxL, p->mCtoL, INT_MAX - 1 } ) );

// Avoid to push_back() same as previous points.
Point prevPt(INT_MIN, INT_MIN);

// Bezier to Line
for(int i = 0;i <= p->mCtoL; i++){
for(int i = 0;i <= iCtoL; i++){
// Split Bezier to lines ( in FreeType coordinates ).
double u = (double)i * 1.0 / (p->mCtoL) ;
double nu = 1.0 - u;
double p0 = nu * nu;
double p1 = 2.0 * u * nu;
double p2 = u * u;
const double u = static_cast<double>(i) / iCtoL;
const double nu = 1.0 - u;
const double p0 = nu * nu;
const double p1 = 2.0 * u * nu;
const double p2 = u * u;

double X = (p->mOldP.x) * p0 + cnt->x * p1 + to->x * p2;
double Y = (p->mOldP.y) * p0 + cnt->y * p1 + to->y * p2;
const double X = (p->mOldP.x) * p0 + cnt->x * p1 + to->x * p2;
const double Y = (p->mOldP.y) * p0 + cnt->y * p1 + to->y * p2;

// Store points to draw( in OpenCV coordinates ).
p->mPts.push_back( Point ( ftd(X), ftd(Y) ) );
const Point pt( ftd(X), ftd(Y) );
if ( pt != prevPt )
{
p->mPts.push_back( pt );
prevPt = pt;
}
}
p->mOldP = *to;
return 0;
Expand All @@ -754,23 +779,51 @@ int FreeType2Impl::cuFn( const FT_Vector *cnt1,

PathUserData *p = (PathUserData *)user;

// Calicurate upper limit of CtoL.
// It is same as total length of polylines{ mOldP, cnt1, cnt2, to }.

const double dx1 = p->mOldP.x - cnt1->x;
const double dy1 = p->mOldP.y - cnt1->y;
const double dx2 = cnt1->x - cnt2->x;
const double dy2 = cnt1->y - cnt2->y;
const double dx3 = cnt2->x - to->x;
const double dy3 = cnt2->y - to->y;

const int maxL = static_cast<int>(
std::sqrt( dx1 * dx1 + dy1 * dy1 ) +
std::sqrt( dx2 * dx2 + dy2 * dy2 ) +
std::sqrt( dx3 * dx3 + dy3 * dy3 )
);

// iCtoL should be less than INT_MAX to avoid overflowing for int i.
// iCtoL should not be 0 to avoid dividing 0 for double u.
const int iCtoL = std::max( 1, std::min( { maxL, p->mCtoL, INT_MAX - 1 } ) );

// Avoid to push_back() same as previous points.
Point prevPt(INT_MIN, INT_MIN);

// Bezier to Line
for(int i = 0; i <= p->mCtoL ;i++){
for(int i = 0; i <= iCtoL ;i++){
// Split Bezier to lines ( in FreeType coordinates ).
double u = (double)i * 1.0 / (p->mCtoL) ;
double nu = 1.0 - u;
double p0 = nu * nu * nu;
double p1 = 3.0 * u * nu * nu;
double p2 = 3.0 * u * u * nu;
double p3 = u * u * u;

double X = (p->mOldP.x) * p0 + (cnt1->x) * p1 +
(cnt2->x ) * p2 + (to->x ) * p3;
double Y = (p->mOldP.y) * p0 + (cnt1->y) * p1 +
(cnt2->y ) * p2 + (to->y ) * p3;
const double u = static_cast<double>(i) / iCtoL;
const double nu = 1.0 - u;
const double p0 = nu * nu * nu;
const double p1 = 3.0 * u * nu * nu;
const double p2 = 3.0 * u * u * nu;
const double p3 = u * u * u;

const double X = (p->mOldP.x) * p0 + (cnt1->x) * p1 +
(cnt2->x ) * p2 + (to->x ) * p3;
const double Y = (p->mOldP.y) * p0 + (cnt1->y) * p1 +
(cnt2->y ) * p2 + (to->y ) * p3;

// Store points to draw( in OpenCV coordinates ).
p->mPts.push_back( Point ( ftd(X), ftd(Y) ) );
const Point pt( ftd(X), ftd(Y) );
if ( pt != prevPt )
{
p->mPts.push_back( pt );
prevPt = pt;
}
}
p->mOldP = *to;
return 0;
Expand Down
117 changes: 108 additions & 9 deletions modules/freetype/test/test_basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,59 @@ struct MattypeParams
bool expect_success;
};

::std::ostream& operator<<(::std::ostream& os, const MattypeParams& prm) {
return os << prm.title;
::std::ostream& operator<<(::std::ostream& os, const MattypeParams& prm)
{
os << "title = " << prm.title << " ";
os << "mattype = ";

switch( CV_MAT_DEPTH( prm.mattype ) )
{
case CV_8U: os << "CV_8U" ; break;
case CV_8S: os << "CV_8S" ; break;
case CV_16U: os << "CV_16U"; break;
case CV_16S: os << "CV_16S"; break;
case CV_32S: os << "CV_32S"; break;
case CV_32F: os << "CV_32F"; break;
case CV_64F: os << "CV_64F"; break;
case CV_16F: os << "CV_16F"; break;

// OpenCV5
#ifdef CV_16BF
case CV_16BF: os << "CV_16BF"; break;
#endif
#ifdef CV_Bool
case CV_Bool: os << "CV_Bool"; break;
#endif
#ifdef CV_64U
case CV_64U: os << "CV_64U"; break;
#endif
#ifdef CV_64S
case CV_64S: os << "CV_64S"; break;
#endif
#ifdef CV_32U
case CV_32U: os << "CV_32U"; break;
#endif
default: os << "CV UNKNOWN_DEPTH(" << CV_MAT_DEPTH( prm.mattype ) << ")" ; break;
}

switch( CV_MAT_CN( prm.mattype ) )
{
case 1: os << "C1" ; break;
case 2: os << "C2" ; break;
case 3: os << "C3" ; break;
case 4: os << "C4" ; break;
default: os << "UNKNOWN_CN" << CV_MAT_CN( prm.mattype ) << ")" ; break;
}

os << " expected = " << (prm.expect_success? "true": "false") ;

return os;
}

const MattypeParams mattype_list[] =
{
{ "CV_8UC1", CV_8UC1, true}, { "CV_8UC2", CV_8UC2, false},
{ "CV_8UC3", CV_8UC3, true}, { "CV_8UC4", CV_8UC4, true},

{ "CV_8SC1", CV_8SC1, false}, { "CV_8SC2", CV_8SC2, false},
{ "CV_8SC3", CV_8SC3, false}, { "CV_8SC4", CV_8SC4, false},
{ "CV_16UC1", CV_16UC1, false}, { "CV_16UC2", CV_16UC2, false},
Expand All @@ -34,7 +78,35 @@ const MattypeParams mattype_list[] =
{ "CV_64FC1", CV_64FC1, false}, { "CV_64FC2", CV_64FC2, false},
{ "CV_64FC3", CV_64FC3, false}, { "CV_64FC4", CV_64FC4, false},
{ "CV_16FC1", CV_16FC1, false}, { "CV_16FC2", CV_16FC2, false},
{ "CV_16FC3", CV_16FC3, false}, { "CV_16FC4", CV_16FC4, false},
{ "CV_16FC3", CV_16FC3, false}, { "CV_16FC4", CV_16FC4, false}

// OpenCV5
#ifdef CV_16BF
,
{ "CV_16BFC1", CV_16BFC1, false}, { "CV_16FC2", CV_16BFC2, false},
{ "CV_16BFC3", CV_16BFC3, false}, { "CV_16FC4", CV_16BFC4, false}
#endif
#ifdef CV_Bool
,
{ "CV_BoolC1", CV_BoolC1, false}, { "CV_BoolC2", CV_BoolC2, false},
{ "CV_BoolC3", CV_BoolC3, false}, { "CV_BoolC4", CV_BoolC4, false}
#endif
#ifdef CV_64U
,
{ "CV_64UC1", CV_64UC1, false}, { "CV_64UC2", CV_64UC2, false},
{ "CV_64UC3", CV_64UC3, false}, { "CV_64UC4", CV_64UC4, false}
#endif
#ifdef CV_64S
,
{ "CV_64SC1", CV_64SC1, false}, { "CV_64SC2", CV_64SC2, false},
{ "CV_64SC3", CV_64SC3, false}, { "CV_64SC4", CV_64SC4, false}
#endif
#ifdef CV_32U
,
{ "CV_32UC1", CV_32UC1, false}, { "CV_32UC2", CV_32UC2, false},
{ "CV_32UC3", CV_32UC3, false}, { "CV_32UC4", CV_32UC4, false}
#endif

};

/******************
Expand Down Expand Up @@ -145,26 +217,53 @@ TEST_P(ctol_range, success)
const string root = cvtest::TS::ptr()->get_data_path();
const string fontdata = root + "freetype/mplus/Mplus1-Regular.ttf";
EXPECT_NO_THROW( ft2->loadFontData( fontdata, 0 ) );
EXPECT_NO_THROW( ft2->setSplitNumber(GetParam()) );

int ctol = GetParam();

if ( ctol < 1 )
{
EXPECT_THROW( ft2->setSplitNumber(GetParam()), cv::Exception );
}
else
{
EXPECT_NO_THROW( ft2->setSplitNumber(GetParam()) );
}

Mat dst(600,600, CV_8UC3, Scalar::all(255) );
Scalar col(128,64,255,192);
EXPECT_NO_THROW( ft2->putText(dst, "CtoL", Point( 0, 50), 50, col, 1, LINE_4, true ) );
EXPECT_NO_THROW( ft2->putText(dst, "LINE_4: oOpPqQ", Point( 40, 100), 50, col, 1, LINE_4, true ) );
EXPECT_NO_THROW( ft2->putText(dst, "LINE_8: oOpPqQ", Point( 40, 150), 50, col, 1, LINE_8, true ) );
EXPECT_NO_THROW( ft2->putText(dst, "LINE_AA:oOpPqQ", Point( 40, 150), 50, col, 1, LINE_AA, true ) );
EXPECT_NO_THROW( ft2->putText(dst, "LINE_AA:oOpPqQ", Point( 40, 200), 50, col, 1, LINE_AA, true ) );

if (cvtest::debugLevel > 0 )
{
imwrite( cv::format("CtoL%d-MatType.png", GetParam()) , dst );
}
}

const int ctol_list[] =
{
1,
INT_MIN, // invalid min
INT_MIN + 1,
-1,
0, // invalid max
1, // valid min
2,
4,
8,
16,
32,
64,
128,
// INT_MAX -1, // Hang-up
// INT_MAX // Hang-up
256,
512,
1024,
2048,
4096,
8192,
INT_MAX -1,
INT_MAX // valid max
};

INSTANTIATE_TEST_CASE_P(Freetype_setSplitNumber, ctol_range,
Expand Down