diff --git a/addons/ofxSvg/src/ofxSvg.cpp b/addons/ofxSvg/src/ofxSvg.cpp index 4a85953595b..5f553ef239f 100755 --- a/addons/ofxSvg/src/ofxSvg.cpp +++ b/addons/ofxSvg/src/ofxSvg.cpp @@ -185,7 +185,7 @@ ofxSvg::ofxSvg(const of::filesystem::path & fileName) { //-------------------------------------------------------------- bool ofxSvg::load( const of::filesystem::path& fileName ) { - ofFile mainXmlFile( fileName, ofFile::ReadOnly ); + ofFile mainXmlFile( fileName, ofFile::ReadWrite ); ofBuffer tMainXmlBuffer( mainXmlFile ); svgPath = fileName; @@ -1093,6 +1093,9 @@ void ofxSvg::_parsePolylinePolygon( ofXml& tnode, std::shared_ptr aS aSvgPath->path.close(); } } + if( aSvgPath ){ + aSvgPath->getBoundingBox(); + } } // reference: https://www.w3.org/TR/SVG2/paths.html#PathData //-------------------------------------------------------------- @@ -1654,6 +1657,9 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr aSvgPath ) { justInCase++; } + if( aSvgPath ){ + aSvgPath->getBoundingBox(); + } } //-------------------------------------------------------------- @@ -1806,7 +1812,7 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr< if( ofIsStringInString(aStr, "translate")) { auto transStr = aStr; - auto tp = _parseMatrixString(transStr, "translate", false ); + auto tp = _parseMatrixString(transStr, "translate", true ); tp.z = 0.f; ofLogVerbose("ofxSvg::setTransformFromSvgMatrixString") << aele->getTypeAsString() << " name: " << aele->getName() << " translate: " << tp; // apos += tp; @@ -2172,6 +2178,9 @@ std::shared_ptr ofxSvg::add( const ofPath& apath ) { auto path = std::make_shared(); path->path = apath; path->applyStyle(mCurrentCss); + + path->getBoundingBox(); //force the generation of the bounding box in the main thread. + _getPushedGroup()->add(path); recalculateLayers(); mPaths.clear(); diff --git a/addons/ofxSvg/src/ofxSvgCss.cpp b/addons/ofxSvg/src/ofxSvgCss.cpp index 10705d39791..40f77b4dfc4 100644 --- a/addons/ofxSvg/src/ofxSvgCss.cpp +++ b/addons/ofxSvg/src/ofxSvgCss.cpp @@ -436,6 +436,18 @@ std::string ofxSvgCssClass::toString(bool aBPrettyPrint) { return ss.str(); } +//-------------------------------------------------- +std::string ofxSvgCssClass::toString(bool aBPrettyPrint) const { + std::stringstream ss; + for( auto& piter : properties ) { + if(aBPrettyPrint) { + ss << std::endl << " "; + } + ss << piter.first << ":" << piter.second.srcString << ";"; + } + return ss.str(); +} + //-------------------------------------------------- bool ofxSvgCssStyleSheet::parse( std::string aCssString ) { if( aCssString.empty() ) { diff --git a/addons/ofxSvg/src/ofxSvgCss.h b/addons/ofxSvg/src/ofxSvgCss.h index af3b597a392..0cc8a7bfd4b 100644 --- a/addons/ofxSvg/src/ofxSvgCss.h +++ b/addons/ofxSvg/src/ofxSvgCss.h @@ -77,6 +77,7 @@ class ofxSvgCssClass { ofColor getColor(const std::string& akey, const ofColor& adefault); std::string toString(bool aBPrettyPrint=true); + std::string toString(bool aBPrettyPrint=true) const; protected: Property dummyProp; diff --git a/addons/ofxSvg/src/ofxSvgElements.cpp b/addons/ofxSvg/src/ofxSvgElements.cpp index cf7d0ef8692..f84b6e0a1f4 100755 --- a/addons/ofxSvg/src/ofxSvgElements.cpp +++ b/addons/ofxSvg/src/ofxSvgElements.cpp @@ -96,7 +96,9 @@ string ofxSvgElement::getCleanName() { {std::regex("_x28_"), "("}, {std::regex("_x29_"), ")"}, {std::regex("_x3B_"), ";"}, - {std::regex("_x2C_"), ","} + {std::regex("_x2C_"), ","}, + {std::regex("_x5B_"), "["}, + {std::regex("_x5D_"), "]"} }; for (const auto& [regexPattern, replacement] : tregs) { @@ -356,6 +358,21 @@ std::vector ofxSvgText::splitWordsAndLineEndings(const std::string& } // build the text spans from a string and not from xml / svg file structure // +//-------------------------------------------------------------- +void ofxSvgText::setText( const std::string& astring ) { + setText(astring, -1.f); +} + +//-------------------------------------------------------------- +void ofxSvgText::setText( const std::string& astring, float aMaxWidth ) { + if( textSpans.size() > 0 ) { + auto tspanClass = textSpans[0]->getCssClass(); + setText(astring, tspanClass, aMaxWidth ); + } else { + setText(astring, mSvgCssClass.getFontFamily("Arial"), mSvgCssClass.getFontSize(18), aMaxWidth ); + } +} + //-------------------------------------------------------------- void ofxSvgText::setText( const std::string& astring, std::string aFontFamily, int aFontSize, float aMaxWidth ) { ofxSvgCssClass css; @@ -369,14 +386,19 @@ void ofxSvgText::setText( const std::string& astring, std::string aFontFamily, i void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvgCssClass, float aMaxWidth ) { meshes.clear(); textSpans.clear(); - + if( astring.empty() ) { ofLogWarning("ofxSvgText::setText") << "string argument is empty. "; return; } + + // set the true for debugging. + bool bVerbose = false; + + bool bCreateNewTextSpanPerLine = mBCreateNewTextSpanPerLine; auto spanStrings = splitBySpanTags(astring); - // ofLogNotice("ofxSvgText") << "number of strings: " << spanStrings.size(); +// ofLogNotice("ofxSvgText") << "number of strings: " << spanStrings.size(); float ex = 0.f; float ey = 0.f; int spanCounter = 0; @@ -396,9 +418,11 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg // css.addProperty("color", getColor() ); if (spanString.find(" tag.\n"; -// std::cout << " Style: [" << data.style << "]\n"; -// std::cout << " Content: [" << data.content << "]\n"; + if(bVerbose) { + std::cout << "Found tag.\n"; + std::cout << " Style: [" << data.style << "]\n"; + std::cout << " Content: [" << data.content << "]\n"; + } css.addProperties(data.style); if (!data.content.empty() && data.content.back() == ' ') { bLastCharIsSpace = true; @@ -421,9 +445,40 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg auto cspan = std::make_shared(); cspan->applyStyle(css); - + ofLogVerbose("ofxSvgText" ) << "going to try and load: " << spanString << " bold: " << cspan->isBold() << " italic: " << cspan->isItalic(); - if(!ofxSvgFontBook::loadFont(fdirectory, cspan->getFontFamily(), cspan->getFontSize(), cspan->isBold(), cspan->isItalic() )) { + if( spanStrings.size() > 1 ) { + if(bVerbose) { + std::cout << "-------------------------------------" << std::endl; + ofLogNotice("ofxSvgText" ) << "going to try and load: " << spanString << std::endl << "css: " << css.toString(); + for( auto& tw : twords ) { + std::cout << "|" << tw << "|"; + } + std::cout << std::endl << "-------------------------------------" << std::endl; + } + } + + // build a quick string from the words. + std::string tempStr; + for( auto& tw : twords ) { + tempStr += tw; + } + +// if(!ofxSvgFontBook::loadFont(fdirectory, cspan->getFontFamily(), cspan->getFontSize(), cspan->isBold(), cspan->isItalic() )) { + ofTrueTypeFontSettings fsettings(fdirectory, cspan->getFontSize()); + // now determine if there is other languages to load. + // TODO: Add more language support. + auto detectedLang = ofxSvgFontBook::detectLanguage(tempStr); + if( detectedLang == ofxSvgFontBook::TextLanguage::JAPANESE ) { + fsettings.addRanges(ofAlphabet::Japanese); + } else if( detectedLang == ofxSvgFontBook::TextLanguage::CHINESE ) { + fsettings.addRanges(ofAlphabet::Chinese); + } else if( detectedLang == ofxSvgFontBook::TextLanguage::KOREAN ) { + fsettings.addRanges(ofAlphabet::Korean); + } + + if( !ofxSvgFontBook::loadFont(fdirectory, cspan->getCssClass(), fsettings )) { + continue; } @@ -453,21 +508,6 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg bool bWasAStringLineBreak = false; - // std::cout << "_____________________________________________________" << std::endl; - // for( std::size_t i = 0; i < twords.size(); i++ ) { - // auto& token = twords[i]; - // if (token == "\n") { - // std::cout << "[\\n]" << std::endl; - // } else if (token == "\r\n") { - // std::cout << "[\\r\\n]" << std::endl; - // } else if (token == "\r") { - // std::cout << "[\\r]" << std::endl; - // } else { - // std::cout << "[" << token << "]" << std::endl; - // } - // } - // std::cout << "_____________________________________________________" << std::endl; - for( std::size_t i = 0; i < twords.size(); i++ ) { bool bFinalWord = (i == twords.size()-1); @@ -490,7 +530,7 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg // ofLogNotice("textSpan word string") << "|"<rect.x > aMaxWidth || bIsAStringLineBreak > 0 ) { + if( (aMaxWidth > 0.f && ex + cspan->rect.x > aMaxWidth) || bIsAStringLineBreak > 0 ) { // if( ex > aMaxWidth ) { tCurrentString = twords[i]; @@ -517,7 +557,12 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg ey += font.getLineHeight(); if( ss.str().size() > 0 ) { - // ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|"; +// ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|"; + if( spanStrings.size() > 1 ) { + if(bVerbose) { + ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|"; + } + } textSpans.push_back(cspan); } @@ -535,10 +580,30 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg //ey += font.stringHeight("M"); bAddedBreak = true; if( spanCounter == 0 && i == 0 ) { - + cspan->text = ss.str(); } else { ey += font.getLineHeight(); - ss << std::endl; + if(bCreateNewTextSpanPerLine) { + cspan->text = ss.str(); + if( ss.str().size() > 0 ) { + if( spanStrings.size() > 1 ) { + if(bVerbose) { + ofLogNotice("ofxSvgText") << "LINE Break: adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|"; + } + } + textSpans.push_back(cspan); + } + + cspan = std::make_shared(); + cspan->applyStyle(css); + ss.str(""); + ss.clear(); + // ofLogNotice("Adding a new line I think") << "ss: " <rect.x = ex; + cspan->rect.y = ey; + } else { + ss << std::endl; + } } } @@ -582,7 +647,7 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg // ex += font.getCharWidth('f'); // } cspan->text = ss.str(); - // ofLogNotice("ofxSvgText") << "adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|"; +// ofLogNotice("ofxSvgText") << "adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|"; cspan->rect.height = font.getStringBoundingBox(cspan->text, 0.f, 0.f ).getHeight();//font.stringHeight(cspan->text); if( bFirstBreak ) { cspan->rect.height = font.getLineHeight(); @@ -592,6 +657,11 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg } // ey = cspan->rect.y + cspan->rect.height; //ey += cspan->rect.height; + if( spanStrings.size() > 1 ) { + if(bVerbose) { + ofLogNotice("ofxSvgText") << "Adding cspan: " << textSpans.size() << " x: " << cspan->rect.x << " text: |" << cspan->text << "|"; + } + } textSpans.push_back(cspan); } @@ -605,6 +675,15 @@ void ofxSvgText::setText( const std::string& astring, const ofxSvgCssClass& aSvg create(); } +//-------------------------------------------------------------- +void ofxSvgText::updateText( const std::string& astring, float aMaxWidth) { + if( textSpans.size() ){ + auto css = textSpans[0]->getCssClass(); + setText( astring, css, aMaxWidth ); + } +} + + //-------------------------------------------------------------- void ofxSvgText::create() { meshes.clear(); diff --git a/addons/ofxSvg/src/ofxSvgElements.h b/addons/ofxSvg/src/ofxSvgElements.h index b6b5293375e..f6f136f84ce 100755 --- a/addons/ofxSvg/src/ofxSvgElements.h +++ b/addons/ofxSvg/src/ofxSvgElements.h @@ -240,6 +240,11 @@ class ofxSvgPath : public ofxSvgElement { } } + if( path.getCommands().size() && outlines.size() == 0 ){ + ofLogError("ofxSvgPath::getBoundingBox()" ) << " path outline size is 0 - you may need to call this function in a main thread to get the correct bounds "; + mBBoxNeedsRecalc = true; + } + path.setStrokeWidth(prevStrokeWidth); } return mBounds; @@ -576,9 +581,12 @@ class ofxSvgText : public ofxSvgElement { virtual ofxSvgType getType() override {return OFXSVG_TYPE_TEXT;} ofTrueTypeFont& getFont(); - + void setText( const std::string& astring ); + void setText( const std::string& astring, float aMaxWidth ); void setText( const std::string& astring, std::string aFontFamily, int aFontSize, float aMaxWidth ); void setText( const std::string& astring, const ofxSvgCssClass& aSvgCssClass, float aMaxWidth ); + void updateText( const std::string& astring, float aMaxWidth); + void create(); void customDraw() override; // going to override @@ -622,6 +630,15 @@ class ofxSvgText : public ofxSvgElement { } } + /// \ brief Applied when calling setText() + void setCreateNewTextSpansPerLine(bool ab) { + mBCreateNewTextSpanPerLine = ab; + } + + bool isCreatingNewTextSpanPerLine() { + return mBCreateNewTextSpanPerLine; + } + /// \brief Get the local bounding box of all of the text spans. virtual ofRectangle getBoundingBox() override; @@ -661,6 +678,8 @@ class ofxSvgText : public ofxSvgElement { bool endsWithLineEnding(const std::string& astr); std::vector splitWordsAndLineEndings(const std::string& input); + bool mBCreateNewTextSpanPerLine = false; + }; diff --git a/addons/ofxSvg/src/ofxSvgFontBook.cpp b/addons/ofxSvg/src/ofxSvgFontBook.cpp index f9514a48e10..af7c3c56d36 100644 --- a/addons/ofxSvg/src/ofxSvgFontBook.cpp +++ b/addons/ofxSvg/src/ofxSvgFontBook.cpp @@ -8,6 +8,67 @@ std::map< string, ofxSvgFontBook::Font > ofxSvgFontBook::fonts; ofxSvgFontBook::Font ofxSvgFontBook::defaultBookFont; + + +// Convert UTF-8 string to Unicode codepoints +std::vector ofxSvgFontBook::_utf8ToCodepoints(const std::string& str) { + std::vector codepoints; + size_t i = 0; + while (i < str.size()) { + uint32_t cp = 0; + unsigned char c = str[i]; + if (c < 0x80) { + cp = c; i++; + } else if (c < 0xE0) { + cp = (c & 0x1F) << 6 | (str[i+1] & 0x3F); i += 2; + } else if (c < 0xF0) { + cp = (c & 0x0F) << 12 | (str[i+1] & 0x3F) << 6 | (str[i+2] & 0x3F); i += 3; + } else { + cp = (c & 0x07) << 18 | (str[i+1] & 0x3F) << 12 | (str[i+2] & 0x3F) << 6 | (str[i+3] & 0x3F); i += 4; + } + codepoints.push_back(cp); + } + return codepoints; +} + +ofxSvgFontBook::TextLanguage ofxSvgFontBook::detectLanguage(const std::string& utf8Text) { + auto codepoints = _utf8ToCodepoints(utf8Text); + // TODO: Add more language support. + int japaneseScore = 0; + int koreanScore = 0; + int chineseScore = 0; + + for (uint32_t cp : codepoints) { + // Hiragana — exclusively Japanese + if (cp >= 0x3040 && cp <= 0x309F) japaneseScore += 3; + // Katakana — exclusively Japanese + else if (cp >= 0x30A0 && cp <= 0x30FF) japaneseScore += 3; + // Hangul — exclusively Korean + else if (cp >= 0xAC00 && cp <= 0xD7AF) koreanScore += 3; + else if (cp >= 0x1100 && cp <= 0x11FF) koreanScore += 3; + // CJK Unified Ideographs — shared, but count for Chinese + // Japanese kanji will still trip this, so it's a weak signal + else if (cp >= 0x4E00 && cp <= 0x9FFF) chineseScore += 1; + // CJK Extension A/B + else if (cp >= 0x3400 && cp <= 0x4DBF) chineseScore += 1; + else if (cp >= 0x20000 && cp <= 0x2A6DF) chineseScore += 1; + // Bopomofo — exclusively Traditional Chinese + else if (cp >= 0x02EA && cp <= 0x02EB) chineseScore += 3; + else if (cp >= 0x3100 && cp <= 0x312F) chineseScore += 3; + } + + if (japaneseScore == 0 && koreanScore == 0 && chineseScore == 0) { + return TextLanguage::ENGLISH; + } + + // Japanese and Korean have exclusive characters so trust high scores + if (japaneseScore > koreanScore && japaneseScore > chineseScore) return TextLanguage::JAPANESE; + if (koreanScore > japaneseScore && koreanScore > chineseScore) return TextLanguage::KOREAN; + if (chineseScore > 0) return TextLanguage::CHINESE; + + return TextLanguage::OTHER; +} + //-------------------------------------------------------------- bool ofxSvgFontBook::loadFont(const std::string& aFontFamily, int aFontSize, bool aBBold, bool aBItalic ) { return loadFont(mFontDirectory, aFontFamily, aFontSize, aBBold, aBItalic ); @@ -25,6 +86,32 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, const std: //-------------------------------------------------------------- bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssClass& aCssClass ) { + // create a ttf settings temp + ofTrueTypeFontSettings fsettings(aDirectory,aCssClass.getFontSize(12)); + fsettings.contours = false; + return loadFont( aDirectory, aCssClass, fsettings ); +} + +//-------------------------------------------------------------- +bool ofxSvgFontBook::loadFont( ofxSvgCssClass& aCssClass, ofxSvgFontBook::TextLanguage alanguage ) { + // create a ttf settings temp + ofTrueTypeFontSettings fsettings(mFontDirectory,aCssClass.getFontSize(12)); + fsettings.contours = false; + +// auto detectedLang = ofxSvgFontBook::detectLanguage(tempStr); + if( alanguage == ofxSvgFontBook::TextLanguage::JAPANESE ) { + fsettings.addRanges(ofAlphabet::Japanese); + } else if( alanguage == ofxSvgFontBook::TextLanguage::CHINESE ) { + fsettings.addRanges(ofAlphabet::Chinese); + } else if( alanguage == ofxSvgFontBook::TextLanguage::KOREAN ) { + fsettings.addRanges(ofAlphabet::Korean); + } + + return loadFont( mFontDirectory, aCssClass, fsettings ); +} + +//-------------------------------------------------------------- +bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssClass& aCssClass, ofTrueTypeFontSettings aFontSettings ) { auto fontFamily = aCssClass.getFontFamily("Arial"); auto fontSize = aCssClass.getFontSize(12); bool bBold = aCssClass.isFontBold(); @@ -47,35 +134,30 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssC Font& tfont = fonts[ fkey ]; if (tfont.sizes.count(fontSize) == 0) { bool bHasFontDirectory = false; - // cout << "checking directory: " << fdirectory+"/fonts/" << endl; - std::string fontsDirectory = "";// = ofToDataPath("", true); - if( !aDirectory.empty() ) { - fontsDirectory = aDirectory.string(); - } - if( !ofFile::doesFileExist(fontsDirectory)) { + std::vector fontsDirsToSearch; + + if( !mFontDirectory.empty() ) { if( ofFile::doesFileExist(mFontDirectory)) { - fontsDirectory = mFontDirectory; + fontsDirsToSearch.push_back(ofFilePath::removeTrailingSlash(mFontDirectory) ); } } -// if( !ofFile::doesFileExist(fontsDirectory)) { -//// fs::path fontPath = fs::path(getenv("HOME")) / "Library" / "Fonts"; -// #if defined(TARGET_OSX) -// std::filesystem::path fontPath = std::filesystem::path(getenv("HOME")) / "Library" / "Fonts"; -// if( ofDirectory::doesDirectoryExist(fontPath) ) { -// fontsDirectory = ofToDataPath(fontPath, true); -// } -// #endif -// } - if( !ofFile::doesFileExist( fontsDirectory )) { - fontsDirectory = ofToDataPath("", true); + + if( !aDirectory.empty() ) { + if( ofDirectory::doesDirectoryExist(ofFilePath::removeTrailingSlash(aDirectory))) { + fontsDirsToSearch.push_back(ofFilePath::removeTrailingSlash(aDirectory) ); + } } - if( ofFile::doesFileExist( fontsDirectory )) { - bHasFontDirectory = true; + + + if( fontsDirsToSearch.size() < 1 ) { + fontsDirsToSearch.push_back( ofToDataPath("", true) ); } + bHasFontDirectory = fontsDirsToSearch.size() > 0; + std::vector fontNamesToSearch = {fontFamily}; // sometimes there are fallback fonts included with a comma separator if( ofIsStringInString(fontFamily, ",")) { @@ -90,7 +172,7 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssC -// string _filename, int _fontSize, bool _bAntiAliased, bool _bFullCharacterSet, bool _makeContours, float _simplifyAmt, int _dpi +// string _filename, int _fontSize, bool _bAntiAliased, bool _bFullCharacterSet, bool _makeContours, float _simplifyAmt, int _dpi // first let's see if the fonts are provided. Some system fonts are .dfont that have several of the faces // in them, but OF isn't setup to parse them, so we need each bold, regular, italic, etc to be a .ttf font // string tfontPath = tfont.fontFamily; @@ -105,7 +187,6 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssC bf = false; } - ofLogVerbose("ofxSvgFontBook") << __FUNCTION__ << " : " << fs.str() << " : starting off searching directory : " << fontsDirectory; string tNewFontPath = ""; std::vector subStrs; @@ -122,15 +203,18 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssC } bool bMightHaveFoundTheFont = false; - ofLogVerbose("ofxSvgFontBook") << "trying to load font: " << tfont.fontFamily << " bold: " << bBold << " italic: " << bItalic; + ofLogVerbose("ofxSvgFontBook") << "trying to load font: " << tfont.fontFamily << " bold: " << bBold << " italic: " << bItalic; // bool bFoundTheFont = _recursiveFontDirSearch(fontsDirectory, tfont.fontFamily, tNewFontPath, subStrs, excludeStrs, 0); - for( auto& fontFam : fontNamesToSearch ) { - bool bFoundTheFont = _recursiveFontDirSearch(fontsDirectory, fontFam, tNewFontPath, subStrs, excludeStrs, 0); - if (bFoundTheFont) { - tfontPath = tNewFontPath; - bMightHaveFoundTheFont = true; - ofLogVerbose("ofxSvgFontBook") << "Found the font at " << tfontPath; - break; + for( auto& fontDir : fontsDirsToSearch ) { + ofLogVerbose("ofxSvgFontBook") << __FUNCTION__ << " : " << fs.str() << " : starting off searching directory : " << fontDir; + for( auto& fontFam : fontNamesToSearch ) { + bool bFoundTheFont = _recursiveFontDirSearch(fontDir, fontFam, tNewFontPath, subStrs, excludeStrs, 0); + if (bFoundTheFont) { + tfontPath = tNewFontPath; + bMightHaveFoundTheFont = true; + ofLogVerbose("ofxSvgFontBook") << "Found the font at " << tfontPath; + break; + } } } @@ -139,10 +223,10 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssC #if defined(TARGET_OSX) std::filesystem::path fontPath = std::filesystem::path(getenv("HOME")) / "Library" / "Fonts"; if( ofDirectory::doesDirectoryExist(fontPath) ) { - fontsDirectory = ofToDataPath(fontPath, true); +// fontsDirectory = ofToDataPath(fontPath, true); for( auto& fontFam : fontNamesToSearch ) { - bool bFoundTheFont = _recursiveFontDirSearch(fontsDirectory, fontFam, tNewFontPath, subStrs, excludeStrs, 0); + bool bFoundTheFont = _recursiveFontDirSearch(ofToDataPath(fontPath, true), fontFam, tNewFontPath, subStrs, excludeStrs, 0); if (bFoundTheFont) { tfontPath = tNewFontPath; bMightHaveFoundTheFont = true; @@ -160,10 +244,10 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssC #if defined(TARGET_OSX) std::filesystem::path fontPath = "/Library/Fonts"; if( ofDirectory::doesDirectoryExist(fontPath) ) { - fontsDirectory = ofToDataPath(fontPath, true); +// fontsDirectory = ofToDataPath(fontPath, true); for( auto& fontFam : fontNamesToSearch ) { - bool bFoundTheFont = _recursiveFontDirSearch(fontsDirectory, fontFam, tNewFontPath, subStrs, excludeStrs, 0); + bool bFoundTheFont = _recursiveFontDirSearch(ofToDataPath(fontPath, true), fontFam, tNewFontPath, subStrs, excludeStrs, 0); if (bFoundTheFont) { tfontPath = tNewFontPath; bMightHaveFoundTheFont = true; @@ -175,31 +259,28 @@ bool ofxSvgFontBook::loadFont(const of::filesystem::path& aDirectory, ofxSvgCssC } #endif } - - /*ofDirectory tfDir; - tfDir.listDir( fontsDirectory ); - for( int ff = 0; ff < tfDir.size(); ff++ ) { - ofFile tfFile = tfDir.getFile(ff); - if( tfFile.getExtension() == "ttf" || tfFile.getExtension() == "otf" ) { - cout << ff << " - font family: " << tfont.fontFamily << " file name: " << tfFile.getBaseName() << endl; - if( ofToLower(tfFile.getBaseName()) == ofToLower(tfont.fontFamily) ) { - ofLogNotice(" >> ofxSvgText found font file for " ) << tfont.fontFamily; - tfontPath = tfFile.getAbsolutePath(); - break; - } - } - }*/ } - ofLogVerbose("ofxSvgFontBook") << __FUNCTION__ << " : Trying to load font from: " << tfontPath; + ofLogVerbose("ofxSvgFontBook") << __FUNCTION__ << " : Trying to load font from: " << tfontPath << " adirectory: " << aDirectory; if (tfontPath == "") { bFontLoadOk = false; } else { // load(const std::string& _filename, int _fontSize, bool _bAntiAliased, bool _bFullCharacterSet, bool _makeContours, float _simplifyAmt, int _dpi) - bFontLoadOk = tfont.sizes[fontSize].load(tfontPath, fontSize, true, true, false, 0.5, 72); +// bFontLoadOk = tfont.sizes[fontSize].load(tfontPath, fontSize, true, true, false, 0.5, 72); + + ofTrueTypeFontSettings fsettings = aFontSettings; + fsettings.fontName = tfontPath; + fsettings.fontSize = fontSize; + fsettings.dpi = aFontSettings.dpi == 0 ? 72 : aFontSettings.dpi; + fsettings.addRange(ofUnicode::Latin1Supplement); + fsettings.addRange(ofUnicode::Latin); + fsettings.addRange(ofUnicode::GeneralPunctuation); + bFontLoadOk = tfont.sizes[fontSize].load(fsettings); + + ofLogVerbose("ofxSvgFontBook") << __FUNCTION__ << " : loaded font ("< fonts; + + static std::vector _utf8ToCodepoints(const std::string& str); + static bool _recursiveFontDirSearch(const std::string& afile, const std::string& aFontFamToLookFor, std::string& fontpath, const std::vector& aAddNames, diff --git a/addons/ofxSvg/src/ofxSvgUtils.cpp b/addons/ofxSvg/src/ofxSvgUtils.cpp index 9220932f369..f34a822f0c3 100644 --- a/addons/ofxSvg/src/ofxSvgUtils.cpp +++ b/addons/ofxSvg/src/ofxSvgUtils.cpp @@ -212,8 +212,19 @@ std::string ofxSvgUtils::base64_decode(std::string const& encoded_string, bool r //--------------------------------------------------------------- std::string ofxSvgUtils::base64_encode( const ofPixels& apixels ) { + return base64_encode( apixels, OF_IMAGE_FORMAT_PNG, OF_IMAGE_QUALITY_BEST ); +} + +//--------------------------------------------------------------- +std::string ofxSvgUtils::base64_encode( const ofPixels& apixels, ofImageQualityType aImgQuality ) { + return base64_encode( apixels, OF_IMAGE_FORMAT_PNG, aImgQuality ); +} + +//--------------------------------------------------------------- +std::string ofxSvgUtils::base64_encode( const ofPixels& apixels, ofImageFormat aImgFormat, ofImageQualityType aImgQuality ) { ofBuffer tbuffer; - ofSaveImage(apixels, tbuffer); + // ofSaveImage(const ofPixels & pix, ofBuffer & buffer, ofImageFormat format = OF_IMAGE_FORMAT_PNG, ofImageQualityType qualityLevel = OF_IMAGE_QUALITY_BEST); + ofSaveImage(apixels, tbuffer, aImgFormat, aImgQuality); auto buffStr = tbuffer.getText(); const unsigned char* data = reinterpret_cast(buffStr.data()); return ofxSvgUtils::base64_encode( data, tbuffer.size(), false ); diff --git a/addons/ofxSvg/src/ofxSvgUtils.h b/addons/ofxSvg/src/ofxSvgUtils.h index a63759876e3..9a887290d3f 100644 --- a/addons/ofxSvg/src/ofxSvgUtils.h +++ b/addons/ofxSvg/src/ofxSvgUtils.h @@ -1,6 +1,7 @@ #pragma once #include #include "ofPixels.h" +#include "ofImage.h" // adding this Optional class since std::optional is not a part of all std:: distributions at the moment, looking at you gcc < 10 nh // and not included in older versions of OF on Windows, ie. 12.0. @@ -62,6 +63,8 @@ class ofxSvgUtils { static std::string base64_decode(std::string const& encoded_string, bool remove_linebreaks); static std::string base64_encode( const ofPixels& apixels ); + static std::string base64_encode( const ofPixels& apixels, ofImageQualityType aImgQuality ); + static std::string base64_encode( const ofPixels& apixels, ofImageFormat aImgFormat, ofImageQualityType aImgQuality ); static ofPixels base64_decode(std::string const& encoded_string );