소스 검색

Adapt font size to input

isundil 6 년 전
부모
커밋
1ad34eb483
1개의 변경된 파일62개의 추가작업 그리고 22개의 파일을 삭제
  1. 62 22
      src/commands/is_create.cpp

+ 62 - 22
src/commands/is_create.cpp

@@ -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)