|
|
@@ -66,7 +66,7 @@ struct TextItem {
|
|
|
class TextLines
|
|
|
{
|
|
|
public:
|
|
|
- TextLines(int lineSpacingHeight): lineSpacing(lineSpacingHeight){}
|
|
|
+ TextLines(char _fontSize): fontSize(_fontSize), lineSpacing(_fontSize *.55d){}
|
|
|
|
|
|
void push_back(const TextItem& line)
|
|
|
{
|
|
|
@@ -76,11 +76,13 @@ class TextLines
|
|
|
|
|
|
std::vector<TextItem> lines;
|
|
|
int getHeight() { return height + (lines.empty() ? 0 : (lineSpacing*(lines.size() -1))); }
|
|
|
+ int getFontSize() { return fontSize; }
|
|
|
int getLineSpacing() { return lineSpacing; }
|
|
|
|
|
|
private:
|
|
|
int height = {};
|
|
|
const int lineSpacing;
|
|
|
+ const int fontSize;
|
|
|
};
|
|
|
|
|
|
class ImageWriter
|
|
|
@@ -92,7 +94,7 @@ public:
|
|
|
ImageWriter& SetOutputPath(const Anope::string& filename);
|
|
|
ImageWriter& SetBgColor(long);
|
|
|
ImageWriter& SetFgColor(long);
|
|
|
- ImageWriter& SetFontSize(char);
|
|
|
+ ImageWriter& SetFontSize(char, char);
|
|
|
ImageWriter& SetOffsetTop(long);
|
|
|
ImageWriter& SetFontPath(const Anope::string &);
|
|
|
|
|
|
@@ -109,18 +111,21 @@ protected:
|
|
|
size_t left;
|
|
|
size_t bottom;
|
|
|
size_t right;
|
|
|
- char fontSize;
|
|
|
+ char minFontSize;
|
|
|
+ char maxFontSize;
|
|
|
Anope::string fontPath;
|
|
|
|
|
|
void WriteText(pngwriter &writer, pngwriterfont &font, char fontSize, const TextItem& line, int offsetY, const RGB &rgb) const;
|
|
|
- void WriteDryRun(pngwriter &writer, pngwriterfont& font, char fontSize, const Anope::string &str, TextLines& lines, const RGB &rgb);
|
|
|
+ bool WriteDryRun(pngwriter &writer, pngwriterfont& font, char fontSize, const Anope::string &str, TextLines& lines, const RGB &rgb);
|
|
|
+ TextLines *WriteDryRun(pngwriter &writer, pngwriterfont& font, char minFontSize, char maxFontSize, const std::vector<Anope::string>& lines, const RGB &rgb);
|
|
|
int GetTextLength(pngwriter &writer, pngwriterfont &font, char fontSize, const std::string &str, int maxWidth) const;
|
|
|
};
|
|
|
|
|
|
-ImageWriter& ImageWriter::SetFontSize(char value)
|
|
|
+ImageWriter& ImageWriter::SetFontSize(char min, char max)
|
|
|
{
|
|
|
- Log(LOG_DEBUG) << "Font size: " << (unsigned) value;
|
|
|
- fontSize = value;
|
|
|
+ Log(LOG_DEBUG) << "Font size: [" << (unsigned) min << "; " << (unsigned) max << "]";
|
|
|
+ minFontSize = min;
|
|
|
+ maxFontSize = max;
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
@@ -185,10 +190,14 @@ ImageWriter& ImageWriter::SetQuotePosition(size_t top, size_t left, size_t right
|
|
|
|
|
|
int ImageWriter::GetTextLength(pngwriter &writer, pngwriterfont &font, char fontSize, const std::string &str, int maxWidth) const
|
|
|
{
|
|
|
- int w = writer.get_text_width_utf8(font, fontSize, str.c_str());
|
|
|
- if (w <= maxWidth)
|
|
|
- return str.size();
|
|
|
- return (int) (str.size() * ((double) maxWidth / (double) w));
|
|
|
+ const unsigned len = str.size();
|
|
|
+
|
|
|
+ for (unsigned i =1; i < len; ++i) {
|
|
|
+ const int w = writer.get_text_width_utf8(font, fontSize, str.substr(0, i).c_str());
|
|
|
+ if (w > maxWidth)
|
|
|
+ return i -1;
|
|
|
+ }
|
|
|
+ return len;
|
|
|
}
|
|
|
|
|
|
void ImageWriter::WriteText(pngwriter &writer, pngwriterfont &font, char fontSize, const TextItem& line, int offsetY, const RGB &rgb) const
|
|
|
@@ -196,7 +205,7 @@ void ImageWriter::WriteText(pngwriter &writer, pngwriterfont &font, char fontSiz
|
|
|
writer.plot_text_utf8(font, fontSize, line.px, offsetY +line.py, 0, const_cast<char*>(line.text.c_str()), rgb.r, rgb.g, rgb.b);
|
|
|
}
|
|
|
|
|
|
-void ImageWriter::WriteDryRun(pngwriter &writer, pngwriterfont& font, char fontSize, const Anope::string &str, TextLines& lines, const RGB &rgb)
|
|
|
+bool ImageWriter::WriteDryRun(pngwriter &writer, pngwriterfont& font, char fontSize, const Anope::string &str, TextLines& lines, const RGB &rgb)
|
|
|
{
|
|
|
const char marginSize = lines.getLineSpacing();
|
|
|
int maxLen = GetTextLength(writer, font, fontSize, str.c_str(), right -left -2*marginSize);
|
|
|
@@ -207,8 +216,27 @@ void ImageWriter::WriteDryRun(pngwriter &writer, pngwriterfont& font, char fontS
|
|
|
if (!lines.lines.empty())
|
|
|
py -= lines.getLineSpacing();
|
|
|
lines.push_back(TextItem(writer, font, str.c_str(), written, written +maxLen, left +marginSize, py, fontSize));
|
|
|
+ if (lines.getHeight() +lines.getLineSpacing() > top -bottom)
|
|
|
+ return false;
|
|
|
written += maxLen;
|
|
|
} while (written < str.length());
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+TextLines *ImageWriter::WriteDryRun(pngwriter &writer, pngwriterfont& font, char minFontSize, char maxFontSize, const std::vector<Anope::string> &lines, const RGB &rgb)
|
|
|
+{
|
|
|
+ TextLines *prev = nullptr;
|
|
|
+ char currentFontSize = minFontSize;
|
|
|
+
|
|
|
+ do {
|
|
|
+ TextLines lines(currentFontSize);
|
|
|
+ for (const Anope::string& str: text)
|
|
|
+ if (!WriteDryRun(writer, font, currentFontSize, str, lines, fgColor))
|
|
|
+ return prev;
|
|
|
+ delete prev;
|
|
|
+ prev = new TextLines(lines);
|
|
|
+ } while (currentFontSize++ < maxFontSize);
|
|
|
+ return prev;
|
|
|
}
|
|
|
|
|
|
bool ImageWriter::Build(User *u)
|
|
|
@@ -217,6 +245,7 @@ bool ImageWriter::Build(User *u)
|
|
|
pngwriterfont font(fontPath.c_str(), err);
|
|
|
if (!font.ready())
|
|
|
{
|
|
|
+ Log(LOG_MODULE) << "Error: cannot load font (" << err << ")";
|
|
|
if (u)
|
|
|
u->SendMessage((*instaServ)->GetBotInfo(), "Error: Cannot load font (" +err +")");
|
|
|
return false;
|
|
|
@@ -224,6 +253,7 @@ bool ImageWriter::Build(User *u)
|
|
|
pngwriter writer(1, 1, 0, outputName.c_str());
|
|
|
if (!writer.readfromfile(background.c_str()))
|
|
|
{
|
|
|
+ Log(LOG_MODULE) << "Error: cannot load background image";
|
|
|
if (u)
|
|
|
u->SendMessage((*instaServ)->GetBotInfo(), "Error: Cannot load background image");
|
|
|
return false;
|
|
|
@@ -233,14 +263,22 @@ bool ImageWriter::Build(User *u)
|
|
|
bgColor.a, bgColor.r, bgColor.g, bgColor.b);
|
|
|
|
|
|
size_t i =0;
|
|
|
- TextLines lines(fontSize * 0.55);
|
|
|
- for (const Anope::string& str: text)
|
|
|
- WriteDryRun(writer, font, fontSize, str, lines, fgColor);
|
|
|
- int offsetY = -((top +offsetTop -bottom -lines.getHeight() -lines.getLineSpacing()) /2);
|
|
|
+ TextLines *lines;
|
|
|
+ lines = WriteDryRun(writer, font, minFontSize, maxFontSize, text, fgColor);
|
|
|
+ if (!lines)
|
|
|
+ {
|
|
|
+ Log(LOG_MODULE) << "Error: Too much text does not fit in image";
|
|
|
+ if (u)
|
|
|
+ u->SendMessage((*instaServ)->GetBotInfo(), "Error: Too much text does not fit in image");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Log(LOG_DEBUG) << "Performing real write with font size = " << (unsigned) lines->getFontSize();
|
|
|
+ int offsetY = -((top +offsetTop -bottom -lines->getHeight() -lines->getLineSpacing()) /2);
|
|
|
if (offsetY > 0)
|
|
|
offsetY = 0;
|
|
|
- for (const TextItem& line: lines.lines)
|
|
|
- WriteText(writer, font, fontSize, line, offsetY, fgColor);
|
|
|
+ for (const TextItem& line: lines->lines)
|
|
|
+ WriteText(writer, font, lines->getFontSize(), line, offsetY, fgColor);
|
|
|
+ delete lines;
|
|
|
writer.close();
|
|
|
chmod(outputName.c_str(), 0644);
|
|
|
return true;
|
|
|
@@ -393,12 +431,14 @@ void InstaMessageBufferImpl::OnEndBuffer()
|
|
|
.SetBgColor(readConfigColor(*config, "bgColor", 0xAAA3A5A7))
|
|
|
.SetFgColor(readConfigColor(*config, "fgColor", 0x474255))
|
|
|
.SetFontPath(config->Get<Anope::string>("font", ""))
|
|
|
- .SetFontSize(config->Get<unsigned>("fontSize", 16));
|
|
|
- builder.Build(u);
|
|
|
- u->SendMessage((*instaServ)->GetBotInfo(), "Image exported as " +config->Get<Anope::string>("httpRoot", "") +filename);
|
|
|
+ .SetFontSize(config->Get<unsigned>("minFontSize", 16), config->Get<unsigned>("maxFontSize", 32));
|
|
|
+ if (builder.Build(u))
|
|
|
+ {
|
|
|
+ u->SendMessage((*instaServ)->GetBotInfo(), "Image exported as " +config->Get<Anope::string>("httpRoot", "") +filename);
|
|
|
+ new FileRemover(path.c_str());
|
|
|
+ }
|
|
|
(*instaServ)->OnExpire(u);
|
|
|
TimerManager::DelTimer(this);
|
|
|
- new FileRemover(path.c_str());
|
|
|
}
|
|
|
|
|
|
MODULE_INIT(ISCreate)
|