|
|
@@ -0,0 +1,292 @@
|
|
|
+
|
|
|
+#include <pngwriter.h>
|
|
|
+#include "instaserv.h"
|
|
|
+
|
|
|
+static ServiceReference<InstaServCore> instaServ("InstaServService", "InstaServ");
|
|
|
+
|
|
|
+class ISCreate;
|
|
|
+
|
|
|
+struct RGB
|
|
|
+{
|
|
|
+ RGB();
|
|
|
+ RGB(long value);
|
|
|
+
|
|
|
+ int r, g, b;
|
|
|
+};
|
|
|
+
|
|
|
+struct ARGB: public RGB
|
|
|
+{
|
|
|
+ ARGB();
|
|
|
+ ARGB(long value);
|
|
|
+
|
|
|
+ double a;
|
|
|
+};
|
|
|
+
|
|
|
+RGB::RGB()
|
|
|
+{
|
|
|
+ r = g = b = 0;
|
|
|
+}
|
|
|
+
|
|
|
+RGB::RGB(long value)
|
|
|
+{
|
|
|
+ const double factor = 65535.d / 255.d;
|
|
|
+ r = ((unsigned char)(value >> 16)) * factor;
|
|
|
+ g = ((unsigned char) (value >> 8)) * factor;
|
|
|
+ b = ((unsigned char) value) * factor;
|
|
|
+}
|
|
|
+
|
|
|
+ARGB::ARGB()
|
|
|
+{
|
|
|
+ a = r = g = b = 0;
|
|
|
+}
|
|
|
+
|
|
|
+ARGB::ARGB(long value): RGB(value)
|
|
|
+{
|
|
|
+ a = ((unsigned char)(value >> 24) / 255.d);
|
|
|
+}
|
|
|
+
|
|
|
+class ImageWriter
|
|
|
+{
|
|
|
+public:
|
|
|
+ ImageWriter& SetBackground(const Anope::string& path);
|
|
|
+ ImageWriter& SetText(const std::vector<Anope::string>& text);
|
|
|
+ ImageWriter& SetQuotePosition(size_t top, size_t left, size_t bottom, size_t right);
|
|
|
+ ImageWriter& SetOutputPath(const Anope::string& filename);
|
|
|
+ ImageWriter& SetBgColor(long);
|
|
|
+ ImageWriter& SetFgColor(long);
|
|
|
+ ImageWriter& SetFontSize(char);
|
|
|
+ ImageWriter& SetFontPath(const Anope::string &);
|
|
|
+
|
|
|
+ bool Build(User* u);
|
|
|
+
|
|
|
+protected:
|
|
|
+ Anope::string background;
|
|
|
+ std::vector<Anope::string> text;
|
|
|
+ Anope::string outputName;
|
|
|
+ ARGB bgColor;
|
|
|
+ RGB fgColor;
|
|
|
+ size_t top;
|
|
|
+ size_t left;
|
|
|
+ size_t bottom;
|
|
|
+ size_t right;
|
|
|
+ char fontSize;
|
|
|
+ Anope::string fontPath;
|
|
|
+
|
|
|
+ void WriteText(pngwriter &writer, pngwriterfont &font, char fontSize, char *str, int strFrom, int strTo, int px, int py, const RGB &rgb) const;
|
|
|
+ int WriteText(pngwriter &writer, pngwriterfont &font, char fontSize, const Anope::string &str, int lineIndex, const RGB &rgb);
|
|
|
+ int GetTextLength(pngwriter &writer, pngwriterfont &font, char fontSize, char *str, int maxWidth) const;
|
|
|
+};
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetFontSize(char value)
|
|
|
+{
|
|
|
+ fontSize = value;
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetFontPath(const Anope::string& value)
|
|
|
+{
|
|
|
+ fontPath = value;
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetBackground(const Anope::string& path)
|
|
|
+{
|
|
|
+ background = path;
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetText(const std::vector<Anope::string>& txt)
|
|
|
+{
|
|
|
+ text = txt;
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetOutputPath(const Anope::string& path)
|
|
|
+{
|
|
|
+ outputName = path;
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetBgColor(long value)
|
|
|
+{
|
|
|
+ bgColor = ARGB(value);
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetFgColor(long value)
|
|
|
+{
|
|
|
+ fgColor = RGB(value);
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+ImageWriter& ImageWriter::SetQuotePosition(size_t top, size_t left, size_t right, size_t bottom)
|
|
|
+{
|
|
|
+ this->top = top;
|
|
|
+ this->left = left;
|
|
|
+ this->bottom = bottom;
|
|
|
+ this->right = right;
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+int ImageWriter::GetTextLength(pngwriter &writer, pngwriterfont &font, char fontSize, char *str, int maxWidth) const
|
|
|
+{
|
|
|
+ int w = writer.get_text_width(font, fontSize, str);
|
|
|
+ if (w <= maxWidth)
|
|
|
+ return strlen(str);
|
|
|
+ return (int) (strlen(str) * ((double) maxWidth / (double) w));
|
|
|
+}
|
|
|
+
|
|
|
+void ImageWriter::WriteText(pngwriter &writer, pngwriterfont &font, char fontSize,
|
|
|
+ char *str, int strFrom, int strTo,
|
|
|
+ int px, int py, const RGB &rgb) const
|
|
|
+{
|
|
|
+ char tmp = str[strTo];
|
|
|
+ str[strTo] = 0;
|
|
|
+ writer.plot_text(font, fontSize, px, py, 0, str +strFrom, rgb.r, rgb.g, rgb.b);
|
|
|
+ str[strTo] = tmp;
|
|
|
+}
|
|
|
+
|
|
|
+int ImageWriter::WriteText(pngwriter &writer, pngwriterfont& font, char fontSize, const Anope::string &str, int lineIndex, const RGB &rgb)
|
|
|
+{
|
|
|
+ const char lineHeight = fontSize +6,
|
|
|
+ marginSize = 10;
|
|
|
+ char *cstrFull = strdup(str.c_str());
|
|
|
+ int maxLen = GetTextLength(writer, font, fontSize, cstrFull, right -left -2*marginSize);
|
|
|
+ int written = 0;
|
|
|
+
|
|
|
+ do {
|
|
|
+ WriteText(writer, font, fontSize, cstrFull, written, written +maxLen, left +marginSize, top -marginSize -(lineHeight * lineIndex) -(fontSize), rgb);
|
|
|
+ written += maxLen;
|
|
|
+ ++lineIndex;
|
|
|
+ } while (written < str.length());
|
|
|
+
|
|
|
+ free(cstrFull);
|
|
|
+ return lineIndex;
|
|
|
+}
|
|
|
+
|
|
|
+bool ImageWriter::Build(User *u)
|
|
|
+{
|
|
|
+ std::string err;
|
|
|
+ pngwriterfont font(fontPath.c_str(), err);
|
|
|
+ if (!font.ready())
|
|
|
+ {
|
|
|
+ if (u)
|
|
|
+ u->SendMessage((*instaServ)->GetBotInfo(), "Error: Cannot load font (" +err +")");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ pngwriter writer(1, 1, 0, outputName.c_str());
|
|
|
+ if (!writer.readfromfile(background.c_str()))
|
|
|
+ {
|
|
|
+ if (u)
|
|
|
+ u->SendMessage((*instaServ)->GetBotInfo(), "Error: Cannot load background image");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ writer.filledsquare_blend(left, top, right, bottom,
|
|
|
+ bgColor.a, bgColor.r, bgColor.g, bgColor.b);
|
|
|
+
|
|
|
+ size_t i =0;
|
|
|
+ for (const Anope::string& str: text)
|
|
|
+ i = WriteText(writer, font, fontSize, str, i, fgColor);
|
|
|
+ writer.close();
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+class InstaMessageBufferImpl: public InstaMessageBuffer, public Timer
|
|
|
+{
|
|
|
+ std::vector<Anope::string> lines;
|
|
|
+ User *u;
|
|
|
+ ISCreate *module;
|
|
|
+
|
|
|
+public:
|
|
|
+ InstaMessageBufferImpl(ISCreate *m, User *user);
|
|
|
+
|
|
|
+ void Tick(time_t t) anope_override;
|
|
|
+ void Add(Anope::string &msg) anope_override;
|
|
|
+ size_t LineCount() const anope_override;
|
|
|
+ void OnEndBuffer() anope_override;
|
|
|
+};
|
|
|
+
|
|
|
+class CommandISCreate : public Command
|
|
|
+{
|
|
|
+ ISCreate *creator;
|
|
|
+public:
|
|
|
+ CommandISCreate(ISCreate *c, const Anope::string &sname = "instaserv/create") : Command((Module*) c, sname, 0, 0), creator(c)
|
|
|
+ {
|
|
|
+ this->SetDesc(_("Create a new quote"));
|
|
|
+ this->SetSyntax("");
|
|
|
+ }
|
|
|
+
|
|
|
+ void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override
|
|
|
+ {
|
|
|
+ if (!source.GetUser())
|
|
|
+ return;
|
|
|
+ source.Reply("Type in your quote, end with a line only containing `EOF'");
|
|
|
+ instaServ->SetBuffer(source.GetUser(), new InstaMessageBufferImpl(creator, source.GetUser()));
|
|
|
+ }
|
|
|
+
|
|
|
+ bool OnHelp(CommandSource &source, const Anope::string &) anope_override
|
|
|
+ {
|
|
|
+ this->SendSyntax(source);
|
|
|
+ source.Reply(_(" \n"
|
|
|
+ "Create a new quote image"));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+class ISCreate : public Module
|
|
|
+{
|
|
|
+ CommandISCreate commandiscreate;
|
|
|
+
|
|
|
+ public:
|
|
|
+ ISCreate(const Anope::string &modname, const Anope::string &creator);
|
|
|
+ size_t GetMaxLines()
|
|
|
+ {
|
|
|
+ return 5;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+ISCreate::ISCreate(const Anope::string &modname, const Anope::string &creator): Module(modname, creator, VENDOR), commandiscreate(this)
|
|
|
+{}
|
|
|
+
|
|
|
+InstaMessageBufferImpl::InstaMessageBufferImpl(ISCreate *m, User *user) :Timer(*instaServ, Config->GetModule("instaserv")->Get<time_t>("typingtimeout", "1m")), u(user), module(m)
|
|
|
+{}
|
|
|
+
|
|
|
+void InstaMessageBufferImpl::Tick(time_t t)
|
|
|
+{
|
|
|
+ (*instaServ)->OnExpire(u);
|
|
|
+}
|
|
|
+
|
|
|
+void InstaMessageBufferImpl::Add(Anope::string &msg)
|
|
|
+{
|
|
|
+ if (LineCount() < module->GetMaxLines())
|
|
|
+ lines.emplace_back(msg);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ std::stringstream ss;
|
|
|
+ ss << "Cannot paste more than " << module->GetMaxLines() << " lines";
|
|
|
+ u->SendMessage((*instaServ)->GetBotInfo(), ss.str());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+size_t InstaMessageBufferImpl::LineCount() const
|
|
|
+{
|
|
|
+ return lines.size();
|
|
|
+}
|
|
|
+
|
|
|
+void InstaMessageBufferImpl::OnEndBuffer()
|
|
|
+{
|
|
|
+ ImageWriter builder;
|
|
|
+ builder.SetBackground("/tmp/riz_carbo.png")
|
|
|
+ .SetText(lines)
|
|
|
+ .SetOutputPath("/srv/http/instaserv/out.png")
|
|
|
+ .SetQuotePosition(458, 10, 614, 10)
|
|
|
+ .SetBgColor(0xAAA3A5A7)
|
|
|
+ .SetFgColor(0x474255)
|
|
|
+ .SetFontPath("/home/isundil/projects/anope/testinstall/data/monoid.ttf")
|
|
|
+ .SetFontSize(16);
|
|
|
+ builder.Build(u);
|
|
|
+ (*instaServ)->OnExpire(u);
|
|
|
+}
|
|
|
+
|
|
|
+MODULE_INIT(ISCreate)
|