From b2bb3d6eef661438955a97758c21df3d8f7ece41 Mon Sep 17 00:00:00 2001 From: razaq Date: Mon, 30 Oct 2023 17:24:30 +0100 Subject: [PATCH 1/3] add function to load font from buffer --- modules/freetype/include/opencv2/freetype.hpp | 13 ++++++++ modules/freetype/src/freetype.cpp | 32 ++++++++++++++++--- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/modules/freetype/include/opencv2/freetype.hpp b/modules/freetype/include/opencv2/freetype.hpp index e62d058a876..a1027c9f8a1 100644 --- a/modules/freetype/include/opencv2/freetype.hpp +++ b/modules/freetype/include/opencv2/freetype.hpp @@ -84,6 +84,19 @@ The function loadFontData loads font data. CV_WRAP virtual void loadFontData(String fontFileName, int idx) = 0; +/** @brief Load font data. + +The function loadFontData loads font data. +The data is not copied, the user needs to make sure the data lives at least as long as FreeType2. +After the FreeType2 object is destroyed, the buffer can be safely deallocated. + +@param pBuf pointer to buffer containing font data +@param bufSize size of buffer +@param idx face_index to select a font faces in a single file. +*/ + + CV_WRAP virtual void loadFontData(uchar* pBuf, size_t bufSize, int idx) = 0; + /** @brief Set Split Number from Bezier-curve to line The function setSplitNumber set the number of split points from bezier-curve to line. diff --git a/modules/freetype/src/freetype.cpp b/modules/freetype/src/freetype.cpp index b8e605e5104..78baf9a2dd4 100644 --- a/modules/freetype/src/freetype.cpp +++ b/modules/freetype/src/freetype.cpp @@ -67,6 +67,7 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2 FreeType2Impl(); ~FreeType2Impl(); void loadFontData(String fontFileName, int idx) CV_OVERRIDE; + void loadFontData(uchar* pBuf, size_t bufSize, int idx) CV_OVERRIDE; void setSplitNumber( int num ) CV_OVERRIDE; void putText( InputOutputArray img, const String& text, Point org, @@ -181,16 +182,39 @@ FreeType2Impl::~FreeType2Impl() void FreeType2Impl::loadFontData(String fontFileName, int idx) { CV_Assert( idx >= 0 ); - if( mIsFaceAvailable == true ) + if ( mIsFaceAvailable == true ) { - hb_font_destroy (mHb_font); + hb_font_destroy(mHb_font); + CV_Assert(!FT_Done_Face(mFace)); + } + + mIsFaceAvailable = false; + CV_Assert( !FT_New_Face( mLibrary, fontFileName.c_str(), static_cast(idx), &mFace ) ); + + mHb_font = hb_ft_font_create(mFace, NULL); + if ( mHb_font == NULL ) + { + CV_Assert(!FT_Done_Face(mFace)); + return; + } + CV_Assert( mHb_font != NULL ); + mIsFaceAvailable = true; +} + +void FreeType2Impl::loadFontData(uchar* pBuf, size_t bufSize, int idx) +{ + CV_Assert( idx >= 0 ); + if ( mIsFaceAvailable == true ) + { + hb_font_destroy(mHb_font); CV_Assert(!FT_Done_Face(mFace)); } mIsFaceAvailable = false; - CV_Assert( !FT_New_Face( mLibrary, fontFileName.c_str(), static_cast(idx), &(mFace) ) ); + FT_Open_Args args{ FT_OPEN_MEMORY, (FT_Byte*)pBuf, static_cast(bufSize), nullptr, nullptr, nullptr, 0, nullptr }; + CV_Assert( !FT_Open_Face(mLibrary, &args, idx, &mFace) ); - mHb_font = hb_ft_font_create (mFace, NULL); + mHb_font = hb_ft_font_create(mFace, NULL); if ( mHb_font == NULL ) { CV_Assert(!FT_Done_Face(mFace)); From 9e71621db8cea169839620d8a04baab33d67e6a0 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 1 Nov 2023 14:19:24 +0300 Subject: [PATCH 2/3] Regression test for the new Freetype method. --- modules/freetype/test/test_basic.cpp | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/modules/freetype/test/test_basic.cpp b/modules/freetype/test/test_basic.cpp index 4c4e0c3d7ce..9dfc05795eb 100644 --- a/modules/freetype/test/test_basic.cpp +++ b/modules/freetype/test/test_basic.cpp @@ -55,6 +55,39 @@ TEST(Freetype_Basic, success ) EXPECT_NO_THROW( ft2->putText(dst, "Basic,success", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); } +TEST(Freetype_Basic, in_memory_font ) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string font_path = root + "freetype/mplus/Mplus1-Regular.ttf"; + + cv::Ptr ft2; + EXPECT_NO_THROW( ft2 = cv::freetype::createFreeType2() ); + EXPECT_NO_THROW( ft2->loadFontData( font_path, 0 ) ); + + Mat dst(600,600, CV_8UC3, Scalar::all(255) ); + Scalar col(128,64,255,192); + EXPECT_NO_THROW( ft2->putText(dst, "Basic,success", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); + + FILE* fp = fopen(font_path.c_str(), "rb"); + ASSERT_TRUE(fp != NULL); + fseek(fp, 0, SEEK_END); + const size_t file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + std::vector font_buffer(file_size); + const size_t actual_read = fread(&font_buffer[0], 1, file_size, fp); + fclose(fp); + ASSERT_EQ(file_size, actual_read); + + cv::Ptr ft2_in_memory; + EXPECT_NO_THROW( ft2_in_memory = cv::freetype::createFreeType2() ); + EXPECT_NO_THROW( ft2_in_memory->loadFontData( &font_buffer[0], file_size, 0 ) ); + Mat dst_in_memory(600,600, CV_8UC3, Scalar::all(255) ); + EXPECT_NO_THROW( ft2_in_memory->putText(dst_in_memory, "Basic,success", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); + + EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), dst, dst_in_memory); +} + /****************** * loadFontData() *****************/ From 9b32dd97e46f1d3e4953cb12550da1fb856ef17b Mon Sep 17 00:00:00 2001 From: Kumataro Date: Thu, 16 Nov 2023 20:43:47 +0900 Subject: [PATCH 3/3] fix for review --- modules/freetype/include/opencv2/freetype.hpp | 6 +-- modules/freetype/src/freetype.cpp | 49 ++++++++++++------- modules/freetype/test/test_basic.cpp | 33 ++++++++++++- 3 files changed, 67 insertions(+), 21 deletions(-) diff --git a/modules/freetype/include/opencv2/freetype.hpp b/modules/freetype/include/opencv2/freetype.hpp index a1027c9f8a1..90007badd1d 100644 --- a/modules/freetype/include/opencv2/freetype.hpp +++ b/modules/freetype/include/opencv2/freetype.hpp @@ -76,7 +76,7 @@ class CV_EXPORTS_W FreeType2 : public Algorithm public: /** @brief Load font data. -The function loadFontData loads font data. +The function loadFontData loads font data from file. @param fontFileName FontFile Name @param idx face_index to select a font faces in a single file. @@ -86,7 +86,7 @@ The function loadFontData loads font data. /** @brief Load font data. -The function loadFontData loads font data. +The function loadFontData loads font data from memory. The data is not copied, the user needs to make sure the data lives at least as long as FreeType2. After the FreeType2 object is destroyed, the buffer can be safely deallocated. @@ -95,7 +95,7 @@ After the FreeType2 object is destroyed, the buffer can be safely deallocated. @param idx face_index to select a font faces in a single file. */ - CV_WRAP virtual void loadFontData(uchar* pBuf, size_t bufSize, int idx) = 0; + CV_WRAP virtual void loadFontData(char* pBuf, size_t bufSize, int idx) = 0; /** @brief Set Split Number from Bezier-curve to line diff --git a/modules/freetype/src/freetype.cpp b/modules/freetype/src/freetype.cpp index 78baf9a2dd4..d8934e361a2 100644 --- a/modules/freetype/src/freetype.cpp +++ b/modules/freetype/src/freetype.cpp @@ -67,7 +67,7 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2 FreeType2Impl(); ~FreeType2Impl(); void loadFontData(String fontFileName, int idx) CV_OVERRIDE; - void loadFontData(uchar* pBuf, size_t bufSize, int idx) CV_OVERRIDE; + void loadFontData(char* pBuf, size_t bufSize, int idx) CV_OVERRIDE; void setSplitNumber( int num ) CV_OVERRIDE; void putText( InputOutputArray img, const String& text, Point org, @@ -88,6 +88,8 @@ class CV_EXPORTS_W FreeType2Impl CV_FINAL : public FreeType2 int mCtoL; hb_font_t *mHb_font; + void loadFontData(FT_Open_Args &args, int idx); + void putTextBitmapMono( InputOutputArray img, const String& text, Point org, int fontHeight, Scalar color, @@ -181,27 +183,41 @@ FreeType2Impl::~FreeType2Impl() void FreeType2Impl::loadFontData(String fontFileName, int idx) { - CV_Assert( idx >= 0 ); - if ( mIsFaceAvailable == true ) + FT_Open_Args args { - hb_font_destroy(mHb_font); - CV_Assert(!FT_Done_Face(mFace)); - } + FT_OPEN_PATHNAME, + nullptr, // memory_base + 0, // memory_size + const_cast(fontFileName.c_str()), + nullptr, // stream + nullptr, // driver + 0, // num_params + nullptr // params + }; - mIsFaceAvailable = false; - CV_Assert( !FT_New_Face( mLibrary, fontFileName.c_str(), static_cast(idx), &mFace ) ); + this->loadFontData(args, idx); +} - mHb_font = hb_ft_font_create(mFace, NULL); - if ( mHb_font == NULL ) +void FreeType2Impl::loadFontData(char* pBuf, size_t bufSize, int idx) +{ + CV_Assert( pBuf != nullptr ); + + FT_Open_Args args { - CV_Assert(!FT_Done_Face(mFace)); - return; - } - CV_Assert( mHb_font != NULL ); - mIsFaceAvailable = true; + FT_OPEN_MEMORY, + reinterpret_cast(pBuf), + static_cast(bufSize), + nullptr, // pathname + nullptr, // stream + nullptr, // driver + 0, // num_params + nullptr // params + }; + + this->loadFontData(args, idx); } -void FreeType2Impl::loadFontData(uchar* pBuf, size_t bufSize, int idx) +void FreeType2Impl::loadFontData(FT_Open_Args &args, int idx) { CV_Assert( idx >= 0 ); if ( mIsFaceAvailable == true ) @@ -211,7 +227,6 @@ void FreeType2Impl::loadFontData(uchar* pBuf, size_t bufSize, int idx) } mIsFaceAvailable = false; - FT_Open_Args args{ FT_OPEN_MEMORY, (FT_Byte*)pBuf, static_cast(bufSize), nullptr, nullptr, nullptr, 0, nullptr }; CV_Assert( !FT_Open_Face(mLibrary, &args, idx, &mFace) ); mHb_font = hb_ft_font_create(mFace, NULL); diff --git a/modules/freetype/test/test_basic.cpp b/modules/freetype/test/test_basic.cpp index 9dfc05795eb..5a646db45f5 100644 --- a/modules/freetype/test/test_basic.cpp +++ b/modules/freetype/test/test_basic.cpp @@ -74,7 +74,7 @@ TEST(Freetype_Basic, in_memory_font ) const size_t file_size = ftell(fp); fseek(fp, 0, SEEK_SET); - std::vector font_buffer(file_size); + std::vector font_buffer(file_size); const size_t actual_read = fread(&font_buffer[0], 1, file_size, fp); fclose(fp); ASSERT_EQ(file_size, actual_read); @@ -138,6 +138,37 @@ TEST(Freetype_loadFontData, call_multiple) EXPECT_NO_THROW( ft2->putText(dst, "call_mutilple", Point( 0, 50), 50, col, -1, LINE_AA, true ) ); } +TEST(Freetype_loadFontDataMemory, nullptr ) +{ + cv::Ptr ft2; + EXPECT_NO_THROW( ft2 = cv::freetype::createFreeType2() ); + EXPECT_ANY_THROW( ft2->loadFontData( nullptr, 0, 0 ) ); +} + +TEST(Freetype_loadFontDataMemory, broken_data ) +{ + const string root = cvtest::TS::ptr()->get_data_path(); + const string font_path = root + "freetype/mplus/Mplus1-Regular.ttf"; + + FILE* fp = fopen(font_path.c_str(), "rb"); + ASSERT_TRUE(fp != NULL); + fseek(fp, 0, SEEK_END); + const size_t file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + std::vector font_buffer(file_size); + const size_t actual_read = fread(&font_buffer[0], 1, file_size, fp); + fclose(fp); + ASSERT_EQ(file_size, actual_read); + + cv::Ptr ft2_in_memory; + EXPECT_NO_THROW( ft2_in_memory = cv::freetype::createFreeType2() ); + + font_buffer[0] = ~font_buffer[0]; // font buffer was broken. + + EXPECT_ANY_THROW( ft2_in_memory->loadFontData( &font_buffer[0], file_size, 0 ) ); +} + typedef testing::TestWithParam idx_range; TEST_P(idx_range, failed )