From d4358844395353e4fce40492945ca559464ee8d8 Mon Sep 17 00:00:00 2001 From: Kumataro Date: Sat, 28 Oct 2023 13:15:15 +0900 Subject: [PATCH 1/2] freetype: fix for huge CtoL param. --- modules/freetype/src/freetype.cpp | 61 +++++++++++++++-- modules/freetype/test/test_basic.cpp | 99 ++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 13 deletions(-) diff --git a/modules/freetype/src/freetype.cpp b/modules/freetype/src/freetype.cpp index b8e605e5104..b30e5a7fe10 100644 --- a/modules/freetype/src/freetype.cpp +++ b/modules/freetype/src/freetype.cpp @@ -723,10 +723,28 @@ 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( + std::pow( dx1 * dx1 + dy1 * dy1, 0.5 ) + + std::pow( dx2 * dx2 + dy2 * dy2, 0.5 ) + ); + + const int iCtoL = std::min( maxL , p->mCtoL ); + + // 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 u = (double)i * 1.0 / (iCtoL) ; double nu = 1.0 - u; double p0 = nu * nu; double p1 = 2.0 * u * nu; @@ -736,7 +754,12 @@ int FreeType2Impl::coFn( const FT_Vector *cnt, 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) ) ); + Point pt ( ftd(X), ftd(Y) ); + if ( pt != prevPt ) + { + p->mPts.push_back( pt ); + prevPt = pt; + } } p->mOldP = *to; return 0; @@ -754,10 +777,31 @@ 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( + std::pow( dx1 * dx1 + dy1 * dy1, 0.5 ) + + std::pow( dx2 * dx2 + dy2 * dy2, 0.5 ) + + std::pow( dx3 * dx3 + dy3 * dy3, 0.5 ) + ); + + const int iCtoL = std::min( maxL, p->mCtoL ); + + // 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 u = (double)i * 1.0 / (iCtoL) ; double nu = 1.0 - u; double p0 = nu * nu * nu; double p1 = 3.0 * u * nu * nu; @@ -770,7 +814,12 @@ int FreeType2Impl::cuFn( const FT_Vector *cnt1, (cnt2->y ) * p2 + (to->y ) * p3; // Store points to draw( in OpenCV coordinates ). - p->mPts.push_back( Point ( ftd(X), ftd(Y) ) ); + Point pt ( ftd(X), ftd(Y) ); + if ( pt != prevPt ) + { + p->mPts.push_back( pt ); + prevPt = pt; + } } p->mOldP = *to; return 0; diff --git a/modules/freetype/test/test_basic.cpp b/modules/freetype/test/test_basic.cpp index 4c4e0c3d7ce..506f920fd3e 100644 --- a/modules/freetype/test/test_basic.cpp +++ b/modules/freetype/test/test_basic.cpp @@ -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}, @@ -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 + }; /****************** @@ -152,19 +224,32 @@ TEST_P(ctol_range, success) 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, + 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 }; INSTANTIATE_TEST_CASE_P(Freetype_setSplitNumber, ctol_range, From 2fab0be19f7bc9ce876af01085022fec62fb2aee Mon Sep 17 00:00:00 2001 From: Kumataro Date: Thu, 9 Nov 2023 18:39:37 +0900 Subject: [PATCH 2/2] fix for review, and re-considering the valid range of iCtoL. --- modules/freetype/src/freetype.cpp | 58 +++++++++++++++------------- modules/freetype/test/test_basic.cpp | 20 ++++++++-- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/modules/freetype/src/freetype.cpp b/modules/freetype/src/freetype.cpp index b30e5a7fe10..0f7c2864877 100644 --- a/modules/freetype/src/freetype.cpp +++ b/modules/freetype/src/freetype.cpp @@ -732,11 +732,13 @@ int FreeType2Impl::coFn( const FT_Vector *cnt, const double dy2 = cnt->y - to->y; const int maxL = static_cast( - std::pow( dx1 * dx1 + dy1 * dy1, 0.5 ) + - std::pow( dx2 * dx2 + dy2 * dy2, 0.5 ) + std::sqrt( dx1 * dx1 + dy1 * dy1 ) + + std::sqrt( dx2 * dx2 + dy2 * dy2 ) ); - const int iCtoL = std::min( maxL , p->mCtoL ); + // 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); @@ -744,17 +746,17 @@ int FreeType2Impl::coFn( const FT_Vector *cnt, // Bezier to Line for(int i = 0;i <= iCtoL; i++){ // Split Bezier to lines ( in FreeType coordinates ). - double u = (double)i * 1.0 / (iCtoL) ; - double nu = 1.0 - u; - double p0 = nu * nu; - double p1 = 2.0 * u * nu; - double p2 = u * u; + const double u = static_cast(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 ). - Point pt ( ftd(X), ftd(Y) ); + const Point pt( ftd(X), ftd(Y) ); if ( pt != prevPt ) { p->mPts.push_back( pt ); @@ -788,12 +790,14 @@ int FreeType2Impl::cuFn( const FT_Vector *cnt1, const double dy3 = cnt2->y - to->y; const int maxL = static_cast( - std::pow( dx1 * dx1 + dy1 * dy1, 0.5 ) + - std::pow( dx2 * dx2 + dy2 * dy2, 0.5 ) + - std::pow( dx3 * dx3 + dy3 * dy3, 0.5 ) + std::sqrt( dx1 * dx1 + dy1 * dy1 ) + + std::sqrt( dx2 * dx2 + dy2 * dy2 ) + + std::sqrt( dx3 * dx3 + dy3 * dy3 ) ); - const int iCtoL = std::min( maxL, p->mCtoL ); + // 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); @@ -801,20 +805,20 @@ int FreeType2Impl::cuFn( const FT_Vector *cnt1, // Bezier to Line for(int i = 0; i <= iCtoL ;i++){ // Split Bezier to lines ( in FreeType coordinates ). - double u = (double)i * 1.0 / (iCtoL) ; - 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(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 ). - Point pt ( ftd(X), ftd(Y) ); + const Point pt( ftd(X), ftd(Y) ); if ( pt != prevPt ) { p->mPts.push_back( pt ); diff --git a/modules/freetype/test/test_basic.cpp b/modules/freetype/test/test_basic.cpp index 506f920fd3e..eb6cc5f8529 100644 --- a/modules/freetype/test/test_basic.cpp +++ b/modules/freetype/test/test_basic.cpp @@ -217,7 +217,17 @@ 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); @@ -234,7 +244,11 @@ TEST_P(ctol_range, success) const int ctol_list[] = { - 1, + INT_MIN, // invalid min + INT_MIN + 1, + -1, + 0, // invalid max + 1, // valid min 2, 4, 8, @@ -249,7 +263,7 @@ const int ctol_list[] = 4096, 8192, INT_MAX -1, - INT_MAX + INT_MAX // valid max }; INSTANTIATE_TEST_CASE_P(Freetype_setSplitNumber, ctol_range,