From 76bc3b3677062c0c1a6b9fa08ff20d12e470159c Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Mon, 4 Nov 2024 02:19:09 -0500 Subject: Some old refactoring + some new refactoring --- wizard.cpp | 569 +++++++++++++------------------------------------------------ 1 file changed, 119 insertions(+), 450 deletions(-) (limited to 'wizard.cpp') diff --git a/wizard.cpp b/wizard.cpp index e4b79e6..4eaefb3 100644 --- a/wizard.cpp +++ b/wizard.cpp @@ -1,443 +1,114 @@ +#include "wizard.h" +#include +#include +#include +#include -#include -#include -#include -#include #include -#include -#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include "prefix_search.h" - - - - +#include +#include +#include "designer.h" +#include "prefix_search.h" -std::string stripSpaces(std::string in) -{ - in.erase( - std::remove_if( - std::begin(in), - std::end(in), - ::isspace), - std::end(in)); +std::string stripSpaces(std::string in) { + in.erase(std::remove_if(std::begin(in), std::end(in), ::isspace), + std::end(in)); return in; } - - - - -using ps_type = prefix_search>; - -enum class card_frame { - m2015, - modern -}; - -struct card { - size_t id; - std::string name; - std::string imageUri; - card_frame frame; - - card( - size_t id, - std::string name, - std::string imageUri, - card_frame frame) : - id(id), - name(std::move(name)), - imageUri(std::move(imageUri)), - frame(frame) - { - } -}; - -struct usage { - size_t cardId; - size_t strIndex; - size_t strLen; - - usage( - size_t ci, - size_t si, - size_t sl) : - cardId(ci), - strIndex(si), - strLen(sl) - { - } -}; - -struct solution { - const ps_type& prefix; - std::vector lengths; - size_t score; -}; - -class designer { -public: - - designer( - std::string text, - const ps_type& titles) : - text_(std::move(text)), - titles_(titles), - solutions_(text_.length() + 1) - { - } - - std::list generate(std::mt19937& rng) const; - - -private: - - const solution& get(size_t i) const; - - solution calculate(size_t i) const; - - const std::string text_; - const ps_type& titles_; - - mutable std::vector> solutions_; -}; - - - - - - - - - -std::list designer::generate(std::mt19937& rng) const -{ - std::list result; - size_t cur = 0; - - while (cur < text_.length()) - { - const solution& curSol = get(cur); - const std::vector& posLens = curSol.lengths; - - std::uniform_int_distribution lenDist(0, posLens.size() - 1); - size_t len = posLens.at(lenDist(rng)); - - const ps_type& prefix = curSol.prefix; - std::uniform_int_distribution cardDist(0, prefix.getCount() - 1); - size_t cardIndex = cardDist(rng); - std::tuple pd = prefix.at(cardIndex); - - result.emplace_back(std::get<0>(pd), std::get<1>(pd), len); - - cur += len; - } - - return result; -} - - - - -solution designer::calculate(size_t i) const -{ - if (i == text_.length()) - { - return { - titles_, - {}, - 0 - }; - } - - const ps_type& prefix = titles_.find(text_, i); - - bool foundScore = false; - size_t bestScore; - std::vector bestLens; - - for (int j = 1; - (j <= prefix.getDepth()) && (i + j <= text_.length()); - j++) - { - const solution& subSol = get(i + j); - - if (subSol.score > 0 || (i + j == text_.length())) - { - size_t tempScore = subSol.score + 1; - - if (!foundScore || tempScore < bestScore) - { - foundScore = true; - bestScore = tempScore; - - bestLens.clear(); - bestLens.push_back(j); - } else if (tempScore == bestScore) - { - bestLens.push_back(j); - } - } - } - - if (!foundScore) - { - return { - titles_, - {}, - 0 - }; - } else { - return { - prefix, - std::move(bestLens), - bestScore - }; - } -} - -const solution& designer::get(size_t i) const -{ - if (!solutions_.at(i)) - { - solutions_[i] = std::make_unique(calculate(i)); - } - - return *solutions_.at(i); -} - - - - -Magick::Image downloadImage(const std::string& url) -{ - std::ostringstream imgbuf; - curl::curl_ios imgios(imgbuf); - curl::curl_easy imghandle(imgios); - - imghandle.add(url.c_str()); - imghandle.add(30); - imghandle.add(300); - - imghandle.perform(); - - if (imghandle.get_info().get() != 200) - { - throw std::runtime_error("Could not download image"); - } - - std::string content_type = imghandle.get_info().get(); - if (content_type.substr(0, 6) != "image/") - { - throw std::runtime_error("Could not download image"); - } - - std::string imgstr = imgbuf.str(); - Magick::Blob img(imgstr.c_str(), imgstr.length()); - - Magick::Image pic; - - try - { - pic.read(img); - } catch (const Magick::ErrorOption& e) - { - // Occurs when the the data downloaded from the server is malformed - std::cout << "Magick: " << e.what() << std::endl; - - throw std::runtime_error("Could not download image"); - } - - return pic; -} - - - - - class tesseract_deleter { -public: - - void operator()(tesseract::TessBaseAPI* ptr) const - { - ptr->End(); - } + public: + void operator()(tesseract::TessBaseAPI* ptr) const { ptr->End(); } }; using tesseract_ptr = - std::unique_ptr; + std::unique_ptr; class pix_deleter { -public: - - void operator()(Pix* ptr) const - { - pixDestroy(&ptr); - } + public: + void operator()(Pix* ptr) const { pixDestroy(&ptr); } }; using pix_ptr = std::unique_ptr; - - - - - -int main(int argc, char** argv) -{ - Magick::InitializeMagick(nullptr); - - std::random_device randomDevice; - std::mt19937 rng(randomDevice()); - - std::cout << "Compiling prefix search..." << std::endl; - - std::vector cards; - ps_type titles; - - std::set chars; - - { - std::ifstream in( - "/Users/hatkirby/Downloads/scryfall-default-cards.json", - std::ios::in | std::ios::binary); - std::ostringstream contents; - contents << in.rdbuf(); - - - nlohmann::json cardsJson = nlohmann::json::parse(contents.str()); - - - - for (const auto& cardJson : cardsJson) - { - if ( - // The object needs to be a card - cardJson["object"] == "card" && - // It needs to have a downloadable image - cardJson.count("image_uris") && - // Make sure we can support the card layout - ( - cardJson["layout"] == "normal" || - cardJson["layout"] == "leveler" || - cardJson["layout"] == "saga" - ) && - // Digital cards look slightly different so ignore them - !cardJson["digital"] && - // Only use english printings - cardJson["lang"] == "en" && - // Currently not supporting silver bordered cards - cardJson["border_color"] != "silver" && - // It is hard to read the name of a planeswalker - cardJson["type_line"].get() - .find("Planeswalker") == std::string::npos && - // This cuts out checklists and special tokens - cardJson["type_line"] != "Card" && - // Amonkhet invocations are impossible - cardJson["set"] != "mp2") - { - card_frame frame; - - if (cardJson["frame"] == "2015") - { - frame = card_frame::m2015; - } else if (cardJson["frame"] == "2003") - { - frame = card_frame::modern; - } else { - continue; - } - - size_t cardId = cards.size(); - cards.emplace_back( - cardId, - cardJson["name"], - cardJson["image_uris"]["png"], - frame); - - std::string canon = hatkirby::lowercase(cardJson["name"]); - - for (int i = 0; i < canon.length(); i++) - { - titles.add(canon, {cardId, i}, i); - - chars.insert(canon.at(i)); - } - } - } - } - +wizard::wizard(std::string cardsPath, std::string cachePath, + std::string outputPath, std::string jsonPath, std::mt19937& rng) + : cards_(cardsPath), + images_(cachePath), + outputPath_(outputPath), + jsonPath_(jsonPath), + rng_(rng) { std::cout << "Characters: "; - for (char ch : chars) - { + + for (char ch : cards_.getCharacters()) { std::cout << ch; } + std::cout << std::endl; +} + +void wizard::run() { + std::string text = "what the heck, it's just some gay guy"; + // getline(std::cin, text); + if (text.back() == '\r') { + text.pop_back(); + } std::cout << "Calculating card list..." << std::endl; - std::string text = "is it pretentious that i'm sending someone over 100 common and uncommon magic cards in an iphone six box"; std::string canonText = hatkirby::lowercase(text); - designer des(canonText, titles); - std::list res = des.generate(rng); + designer des(canonText, cards_.getTitles()); + std::list res = des.generate(rng_); Magick::Image endImage; bool firstSlice = false; + int ui = 0; - for (const usage& u : res) - { - const card& theCard = cards.at(u.cardId); + for (const usage& u : res) { + const card& theCard = cards_.getCard(u.cardId); const std::string& cardName = theCard.name; - std::cout << cardName.substr(0, u.strIndex) - << "[" << cardName.substr(u.strIndex, u.strLen) - << "]" << cardName.substr(u.strIndex + u.strLen) - << std::endl; + std::cout << cardName.substr(0, u.strIndex) << "[" + << cardName.substr(u.strIndex, u.strLen) << "]" + << cardName.substr(u.strIndex + u.strLen) << std::endl; std::cout << "Downloading image..." << std::endl; - Magick::Image cardImg = downloadImage(theCard.imageUri); + Magick::Image cardImg = images_.get(theCard.uuid, theCard.imageUri); std::cout << "Reading text..." << std::endl; Magick::Image titleImg = cardImg; titleImg.magick("TIFF"); - //titleImg.threshold(MaxRGB / 2); + // titleImg.threshold(MaxRGB / 2); titleImg.write("pre.tif"); - Magick::Geometry margin; - if (theCard.frame == card_frame::m2015) - { - margin = Magick::Geometry { 595, 46, 57, 54 }; - } else if (theCard.frame == card_frame::modern) - { - margin = Magick::Geometry { 581, 50, 63, 57 }; + if (theCard.frame == card_frame::m2015) { + margin = Magick::Geometry{595, 46, 57, 54}; + } else if (theCard.frame == card_frame::modern) { + margin = Magick::Geometry{581, 50, 63, 57}; } titleImg.crop(margin); - titleImg.zoom({ margin.width() * 5, margin.height() * 5 }); + titleImg.zoom({margin.width() * 5, margin.height() * 5}); - //titleImg.quantizeColorSpace(Magick::GRAYColorspace); - //titleImg.quantizeColors(2); - //titleImg.quantize(); + // titleImg.quantizeColorSpace(Magick::GRAYColorspace); + // titleImg.quantizeColors(2); + // titleImg.quantize(); titleImg.backgroundColor("white"); titleImg.matte(false); titleImg.resolutionUnits(Magick::PixelsPerInchResolution); - titleImg.density({ 300, 300 }); + titleImg.density({300, 300}); titleImg.type(Magick::GrayscaleType); titleImg.write("title.tif"); @@ -445,15 +116,13 @@ int main(int argc, char** argv) Magick::Blob titleBlob; titleImg.write(&titleBlob); - pix_ptr titlePix { pixReadMemTiff( - reinterpret_cast(titleBlob.data()), - titleBlob.length(), - 0) }; + pix_ptr titlePix{ + pixReadMemTiff(reinterpret_cast(titleBlob.data()), + titleBlob.length(), 0)}; - tesseract_ptr api { new tesseract::TessBaseAPI() }; + tesseract_ptr api{new tesseract::TessBaseAPI()}; - if (api->Init(nullptr, "eng")) - { + if (api->Init(nullptr, "eng")) { throw std::runtime_error("Could not initialize tesseract"); } @@ -463,48 +132,48 @@ int main(int argc, char** argv) tesseract::ResultIterator* ri = api->GetIterator(); tesseract::PageIteratorLevel level = tesseract::RIL_TEXTLINE; bool foundName = false; + size_t extraChars = 0; - if (ri) - { - do - { + if (ri) { + do { const char* line = ri->GetUTF8Text(level); - if (line) - { + if (line) { std::string lineStr(line); - //if (stripSpaces(hatkirby::lowercase(lineStr)).find(stripSpaces(hatkirby::lowercase((cardName)))) == 0) - { + size_t leadin = hatkirby::lowercase(lineStr).find( + hatkirby::lowercase((cardName))); + if (leadin != std::string::npos) { foundName = true; + extraChars = leadin; break; - }/* else { - std::cout << "WRONG: " << lineStr << std::endl; - }*/ + } /* else { + std::cout << "WRONG: " << lineStr << std::endl; + }*/ } } while (ri->Next(level)); } - if (foundName) - { + if (foundName) { level = tesseract::RIL_SYMBOL; + for (int i = 0; i < extraChars; i++) { + ri->Next(level); + } + std::vector> characters; size_t cur = 0; - do - { + do { int x1, y1, x2, y2; ri->BoundingBox(level, &x1, &y1, &x2, &y2); x1 /= 5; x2 /= 5; - if (cardName.at(cur) == ' ') - { - if (cur == 0) - { + if (cardName.at(cur) == ' ') { + if (cur == 0) { characters.emplace_back(0, x1); } else { const auto& prev = characters.back(); @@ -515,73 +184,73 @@ int main(int argc, char** argv) } characters.emplace_back(x1, x2); + std::cout << characters.size() << " " << x1 << "," << x2 << " (" + << ri->GetUTF8Text(level) << ")" << std::endl; cur++; } while (ri->Next(level) && (cur < cardName.length())); - if (cur != cardName.length()) - { + if (cur != cardName.length()) { throw std::runtime_error("Error detecting character bounds"); } - cardImg.crop({ - std::get<1>(characters[u.strIndex + u.strLen - 1]) - - std::get<0>(characters[u.strIndex]), - cardImg.rows(), - margin.xOff() + std::get<0>(characters[u.strIndex]), - 0 - }); - - cardImg.magick("PNG"); - cardImg.write("slice.png"); - } else { - std::cout << "Didn't find name" << std::endl; - } - - + Magick::Image bakImg = cardImg; + unsigned int left = margin.xOff() + std::get<0>(characters[u.strIndex]); + unsigned int right = + margin.xOff() + std::get<1>(characters[u.strIndex + u.strLen - 1]); + cardImg.crop({right - left, cardImg.rows(), left, 0}); + if (ui == 0) { + bakImg.crop({margin.xOff(), bakImg.rows(), 0, 0}); + cardImg.extent({cardImg.columns() + bakImg.columns(), cardImg.rows()}, + "black", Magick::GravityType::EastGravity); + cardImg.composite(bakImg, 0, 0); + } else if (ui == (res.size() - 1)) { + bakImg.crop( + {bakImg.columns() - margin.xOff() - std::get<1>(characters.back()), + bakImg.rows(), margin.xOff() + std::get<1>(characters.back()), 0}); + int xoff = cardImg.columns(); + cardImg.extent({cardImg.columns() + bakImg.columns(), cardImg.rows()}); + cardImg.composite(bakImg, xoff, 0); + } + cardImg.magick("PNG"); + cardImg.write("slice.png"); + } else { + std::cout << "Didn't find name" << std::endl; + } - if (!firstSlice) - { + if (!firstSlice) { firstSlice = true; endImage = cardImg; - } else { + if (theCard.frame == card_frame::m2015) { + // endImage.extent({endImage.columns(), endImage.rows() + 6}, + // Magick::SouthGravity); + } + } else { int xoff = endImage.columns(); endImage.backgroundColor("black"); - endImage.extent( - {endImage.columns() + cardImg.columns(), cardImg.rows()}, - Magick::WestGravity); + endImage.extent({endImage.columns() + cardImg.columns(), cardImg.rows()}, + Magick::WestGravity); - endImage.composite( - cardImg, - xoff, - (theCard.frame == card_frame::m2015) ? 6 : 0); + endImage.composite(cardImg, xoff, + (theCard.frame == card_frame::m2015) ? 6 : 0); } - - //break; + // break; + ui++; } - endImage.magick("PNG"); - endImage.write("output.png"); - - - - - - + endImage.write(outputPath_); } - - -- cgit 1.4.1