/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2024 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ #include "stdafx.h" #include "gdioutput.h" #include #include #include #include #include #include "meos_util.h" #include "Localizer.h" #include "gdiconstants.h" #include "HTMLWriter.h" #include "Printer.h" #include "oListInfo.h" #include "meosexception.h" #include "image.h" extern Image image; #include #include using namespace std; double getLocalScale(const wstring &fontName, wstring &faceName); wstring getMeosCompectVersion(); map > HTMLWriter::tCache; extern wchar_t exePath[MAX_PATH]; static void generateStyles(const gdioutput &gdi, std::ostream &fout, double scale, bool withTbl, const list &TL, map< pair, pair > &styles) { fout << "\n"; } class InterpTextInfo { public: static int x(const TextInfo &ti) { return ti.xp; } static int y(const TextInfo &ti) { return ti.yp; } static const TextInfo &ti(const TextInfo &in_ti) { return in_ti; } }; template void HTMLWriter::formatTL(ostream &fout, ImageWriter& imageWriter, const map, pair> &styles, const T &tl, double &yscale, double &xscale, int &offsetY, int &offsetX) { auto itt = tl.begin(); while (itt != tl.end()) { auto &ctr_it = *itt; const TextInfo &it = TI::ti(ctr_it); if (gdioutput::skipTextRender(it.format)) { ++itt; continue; } string yp = itos(int(yscale*TI::y(ctr_it)) + offsetY); string xp = itos(int(xscale*TI::x(ctr_it)) + offsetX); if ((it.format & 0xFF) == textImage) { int imgW = int((it.textRect.right - it.textRect.left) * xscale); int imgH = int((it.textRect.bottom - it.textRect.top) * xscale); imageWriter.write(fout, xp, yp, it.text, imgW, imgH); ++itt; continue; } string estyle; if (it.format != 1 && it.format != boldSmall) { if (it.format & textRight) estyle = " style=\"position:absolute;left:" + xp + "px;top:" + yp + "px\""; else estyle = " style=\"position:absolute;left:" + xp + "px;top:" + yp + "px\""; } else { if (it.format & textRight) estyle = " style=\"font-weight:bold;position:absolute;left:" + xp + "px;top:" + yp + "px\""; else estyle = " style=\"font-weight:bold;position:absolute;left:" + xp + "px;top:" + yp + "px\""; } string starttag, endtag; getStyle(styles, it.getGdiFont(), gdioutput::narrow(it.font), estyle, starttag, endtag); if (!it.text.empty()) fout << starttag << gdioutput::toUTF8(encodeXML(it.text)) << endtag << endl; if (it.format == boldLarge) { auto next = itt; ++next; if (next == tl.end() || next->yp != it.yp) offsetY += 7; } ++itt; } } static void getStyle(const map< pair, pair > &styles, gdiFonts font, const string &face, const string &extraStyle, string &starttag, string &endtag) { starttag.clear(); endtag.clear(); string extra; switch (font) { case boldText: case boldSmall: extra = "b"; break; case italicSmall: case italicText: case italicMediumPlus: extra = "i"; break; } pair key(font, face); map< pair, pair >::const_iterator res = styles.find(key); if (res != styles.end()) { const pair &stylePair = res->second; if (!stylePair.first.empty()) { starttag = "<" + stylePair.first; if (!stylePair.second.empty()) starttag += " class=\"" + stylePair.second + "\""; starttag += extraStyle; starttag += ">"; } if (!extra.empty()) { starttag += "<" + extra + ">"; endtag = ""; } if (!stylePair.first.empty()) { endtag += ""; } } else { string element; switch(font) { case boldHuge: element="h1"; break; case boldLarge: element="h2"; break; case fontLarge: element="h2"; break; case fontMedium: element="h3"; break; } if (!extraStyle.empty() && element.empty()) element = "div"; if (element.size()>0) { starttag = "<" + element + extraStyle + ">"; } if (!extra.empty()) { starttag += "<" + extra + ">"; endtag = ""; } if (element.size()>0) { endtag += ""; } } } void HTMLWriter::writeHTML(gdioutput &gdi, const wstring &file, const wstring &title, int refreshTimeOut, double scale){ checkWriteAccess(file); ofstream fout(file.c_str()); if (fout.bad()) throw std::exception("Bad output stream"); wchar_t drive[20]; wchar_t dir[MAX_PATH]; wchar_t name[MAX_PATH]; wchar_t ext[MAX_PATH]; _wsplitpath_s(file.c_str(), drive, dir, name, ext); wstring path = wstring(drive) + dir; writeHTML(gdi, fout, title, true, path, refreshTimeOut, scale); } void HTMLWriter::writeHTML(gdioutput& gdi, ostream& fout, const wstring& title, bool includeImages, const wstring& imageDirectoryDestination, int refreshTimeOut, double scale) { ImageWriter imgWriter(imageDirectoryDestination, includeImages); if (scale <= 0) scale = 1.0; fout << "" << endl; fout << "\n\n"; fout << "\n"; if (refreshTimeOut > 0) fout << "\n"; fout << "" << gdioutput::toUTF8(title) << "\n"; map< pair, pair > styles; generateStyles(gdi, fout, scale, false, gdi.getTL(), styles); fout << "\n"; fout << "\n"; double yscale = 1.3 * scale; double xscale = 1.2 * scale; int offsetY = 0, offsetX = 0; HTMLWriter::formatTL, InterpTextInfo>(fout, imgWriter, styles, gdi.getTL(), yscale, xscale, offsetY, offsetX); fout << "

"; char bf1[256]; char bf2[256]; GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256); GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256); //fout << "Skapad av MeOS: " << bf1 << " "<< bf2 << "\n"; fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "MeOS: " << bf1 << " " << bf2 << "\n"; fout << "

\n"; fout << "\n"; fout << "\n"; } wstring html_table_code(const wstring &in) { if (in.size()==0) return L" "; else { return encodeXML(in); } } bool sortTL_X(const TextInfo *a, const TextInfo *b) { return a->xp < b->xp; } void HTMLWriter::writeTableHTML(gdioutput &gdi, const wstring &file, const wstring &title, int refreshTimeOut, double scale) { checkWriteAccess(file); ofstream fout(file.c_str()); if (fout.bad()) return throw std::exception("Bad output stream"); wchar_t drive[20]; wchar_t dir[MAX_PATH]; wchar_t name[MAX_PATH]; wchar_t ext[MAX_PATH]; _wsplitpath_s(file.c_str(), drive, dir, name, ext); wstring path = wstring(drive) + dir; writeTableHTML(gdi, fout, title, true, path, false, refreshTimeOut, scale); } void HTMLWriter::writeTableHTML(gdioutput& gdi, ostream& fout, const wstring& title, bool includeImages, const wstring& imageDirectoryDestination, bool simpleFormat, int refreshTimeOut, double scale) { if (scale <= 0) scale = 1.0; ImageWriter imgWriter(imageDirectoryDestination, includeImages); fout << "" << endl; fout << "\n\n"; fout << "\n"; if (refreshTimeOut > 0) fout << "\n"; fout << "" << gdioutput::toUTF8(title) << "\n"; map< pair, pair > styles; generateStyles(gdi, fout, scale, true, gdi.getTL(), styles); fout << "\n"; fout << "\n"; auto& TL = gdi.getTL(); auto it = TL.begin(); int MaxX = gdi.getPageX() - 100; map tableCoordinates; //Get x-coordinates while (it != TL.end()) { tableCoordinates[it->xp] = 0; ++it; } int kr = 0; map::iterator mit = tableCoordinates.begin(); while (mit != tableCoordinates.end()) { mit->second = kr++; ++mit; } tableCoordinates[MaxX] = kr; vector sizeSet(kr + 1, false); fout << "\n"; int linecounter = 0; it = TL.begin(); vector< pair > > rows; rows.reserve(TL.size() / 3); vector ypRow; int minHeight = 100000; while (it != TL.end()) { int y = it->yp; vector row; int subnormal = 0; int normal = 0; int header = 0; int mainheader = 0; while (it != TL.end() && it->yp == y) { if (!gdioutput::skipTextRender(it->format)) { row.push_back(&*it); switch (it->getGdiFont()) { case fontLarge: case boldLarge: case boldHuge: mainheader++; break; case boldText: case italicMediumPlus: case fontMediumPlus: header++; break; case fontSmall: case italicSmall: subnormal++; break; default: normal++; } } ++it; } if (row.empty()) continue; bool isMainHeader = mainheader > normal; bool isHeader = (header + mainheader) > normal; bool isSub = subnormal > normal; sort(row.begin(), row.end(), sortTL_X); rows.resize(rows.size() + 1); rows.back().first = isMainHeader ? 1 : (isHeader ? 2 : (isSub ? 3 : 0)); rows.back().second.swap(row); int last = ypRow.size(); ypRow.push_back(y); if (last > 0) { minHeight = min(minHeight, ypRow[last] - ypRow[last - 1]); } } int numMin = 0; for (size_t gCount = 1; gCount < rows.size(); gCount++) { int h = ypRow[gCount] - ypRow[gCount - 1]; if (h == minHeight) numMin++; } if (numMin == 0) numMin = 1; int hdrLimit = (rows.size() / numMin) <= 4 ? int(minHeight * 1.2) : int(minHeight * 1.5); for (size_t gCount = 1; gCount + 1 < rows.size(); gCount++) { int type = rows[gCount].first; int lastType = gCount > 0 ? rows[gCount - 1].first : 0; int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0; if (type == 0 && (lastType == 1 || lastType == 2) && (nextType == 1 || nextType == 2)) continue; // No reclassify int h = ypRow[gCount] - ypRow[gCount - 1]; if (h > hdrLimit && rows[gCount].first == 0) rows[gCount].first = 2; } ypRow.clear(); string lineclass; for (size_t gCount = 0; gCount < rows.size(); gCount++) { vector& row = rows[gCount].second; int type = rows[gCount].first; int lastType = gCount > 0 ? rows[gCount - 1].first : 0; int nextType = gCount + 1 < rows.size() ? rows[gCount + 1].first : 0; vector::iterator rit; fout << "" << endl; if (simpleFormat) { } else if (type == 1) { lineclass = " class=\"freeheader\""; linecounter = 0; } else if (type == 2) { linecounter = 0; lineclass = " valign=\"bottom\" class=\"header\""; } else { if (type == 3) linecounter = 1; if ((lastType == 1 || lastType == 2) && (nextType == 1 || nextType == 2) && row.size() < 3) { lineclass = ""; } else lineclass = (linecounter & 1) ? " class=\"e1\"" : " class=\"e0\""; linecounter++; } for (size_t k = 0; k < row.size(); k++) { int thisCol = tableCoordinates[row[k]->xp]; if (k == 0 && thisCol != 0) fout << " "; int nextCol; if (row.size() == k + 1) nextCol = tableCoordinates.rbegin()->second; else nextCol = tableCoordinates[row[k + 1]->xp]; int colspan = nextCol - thisCol; assert(colspan > 0); string style; if (row[k]->format & textRight) style = " style=\"text-align:right\""; if (colspan == 1 && !sizeSet[thisCol]) { fout << " xp - row[k]->xp) : (MaxX - row[k]->xp)) << "\">"; sizeSet[thisCol] = true; } else if (colspan > 1) fout << " "; else fout << " "; if ((row[k]->format & 0xFF) == textImage) { int imgW = int((row[k]->textRect.right - row[k]->textRect.left) * scale); int imgH = int((row[k]->textRect.bottom - row[k]->textRect.top) * scale); imgWriter.write(fout, "", "", row[k]->text, imgW, imgH); fout << "" << endl; } else { gdiFonts font = row[k]->getGdiFont(); string starttag, endtag; getStyle(styles, font, gdioutput::narrow(row[k]->font), "", starttag, endtag); fout << starttag << gdioutput::toUTF8(html_table_code(row[k]->text)) << endtag << "" << endl; } } fout << "\n"; row.clear(); } fout << "
\n"; if (!simpleFormat) { fout << "

"; char bf1[256]; char bf2[256]; GetTimeFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf2, 256); GetDateFormatA(LOCALE_USER_DEFAULT, 0, NULL, NULL, bf1, 256); wstring meos = getMeosCompectVersion(); fout << gdioutput::toUTF8(lang.tl("Skapad av ")) + "MeOS " << gdioutput::toUTF8(meos) << ": " << bf1 << " " << bf2 << "\n"; fout << "


\n"; } fout << "" << endl; fout << "" << endl; } extern wchar_t programPath[MAX_PATH]; void HTMLWriter::enumTemplates(TemplateType type, vector &descriptionFile) { vector res; #ifdef _DEBUG expandDirectory((wstring(programPath) + L".\\..\\Lists\\").c_str(), L"*.template", res); #endif wchar_t listpath[MAX_PATH]; getUserFile(listpath, L""); expandDirectory(listpath, L"*.template", res); if (exePath[0]) expandDirectory(exePath, L"*.template", res); set tags; tCache.clear(); TemplateInfo ti; for (wstring &fn : res) { ifstream file(fn); string str; if (getline(file, str)) { if (str == "@MEOS EXPORT TEMPLATE" && getline(file, str)) { vector tagName; split(str, "@", tagName); if (tagName.size() == 2) { ti.tag = tagName[0]; if (!tags.insert(tagName[0]).second) continue; // Already included string2Wide(tagName[1], ti.name); if (getline(file, str)) { string2Wide(str, ti.desc); } ti.file = fn; if (type == TemplateType::List) descriptionFile.push_back(ti); } else { throw meosException(L"Bad template: " + fn); } } else if (str == "@MEOS PAGE" && getline(file, str)) { vector tagName; split(str, "@", tagName); if (tagName.size() == 2) { ti.tag = tagName[0]; if (!tags.insert(tagName[0]).second) continue; // Already included string2Wide(tagName[1], ti.name); if (getline(file, str)) { string2Wide(str, ti.desc); } ti.file = fn; if (type == TemplateType::Page) descriptionFile.push_back(ti); } else { throw meosException(L"Bad template: " + fn); } } } } } const HTMLWriter &HTMLWriter::getWriter(TemplateType type, const string &tag) { auto res = tCache.find(tag); if (res != tCache.end()) { return *res->second; } else { vector descriptionFile; enumTemplates(type, descriptionFile); int ix = -1; for (size_t k = 0; k < descriptionFile.size(); k++) { if (descriptionFile[k].tag == tag) { ix = k; break; } } if (ix == -1) throw std::exception("Internal error"); shared_ptr tmpl = make_shared(); tmpl->read(descriptionFile[ix].file); vector tagName; split(tmpl->info, "@", tagName); if (tagName.size() == 2) tCache[tagName[0]] = tmpl; return *tmpl; } } string HTMLWriter::localize(const string &in) { string out; size_t offset = 0; size_t pos = in.find_first_of('$', offset); while (pos != string::npos) { if (out.empty()) out.reserve(in.length() * 2); size_t end = in.find_first_of('$', pos+1); if (end != string::npos && end > pos + 2) { wstring key = gdioutput::fromUTF8(in.substr(pos + 1, end - pos - 1)); out += in.substr(offset, pos-offset); if (key[0] != '!') out += gdioutput::toUTF8(lang.tl(key)); else out += gdioutput::toUTF8(lang.tl(key.substr(1), true)); offset = end + 1; pos = in.find_first_of('$', offset); } else break; } if (offset == 0) return trim(in); out += in.substr(offset); return trim(out); } void HTMLWriter::read(const wstring &fileName) { ifstream file(fileName); string dmy; string *acc = &dmy; string str; int ok = 0 ; const string comment = "//"; while (getline(file, str)) { if (ok == 0 && str == "@MEOS EXPORT TEMPLATE") { ok = 1; continue; } else if (ok == 1) { ok = 2; info = str; } else if (ok == 0 && str == "@MEOS PAGE") { ok = 3; continue; } else if (ok == 3) { ok = 4; info = str; acc = &page; continue; } else if (str.length() > 1 && str[0] == '%') continue; // Ignore comment else if (str == "@HEAD") acc = &head; else if (str == "@DESCRIPRION") acc = &description; else if (str == "@OUTERPAGE") acc = &outerpage; else if (str == "@INNERPAGE") acc = &innerpage; else if (str == "@SEPARATOR") acc = &separator; else if (str == "@END") acc = &end; else { size_t cix = str.rfind(comment); if (cix != string::npos) { if (cix == 0) continue; // Comment line else if (cix > 0 && str[cix - 1] != ':') str = str.substr(0, cix); } *acc += localize(str) + "\n"; if (!(str.empty() || acc->back() == '>' || acc->back() == ';' || acc->back() == '}' || acc->back() == '{')) *acc += " "; } } } namespace { void replaceAll(string& str, const string& from, const string& to) { size_t start_pos = 0; while ((start_pos = str.find(from, start_pos)) != string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); } } } class InterpPrintTextInfo { public: static int x(const PrintTextInfo &ti) { return int(ti.xp); } static int y(const PrintTextInfo &ti) { return int(ti.yp); } static const TextInfo &ti(const PrintTextInfo &in_ti) { return in_ti.ti; } }; void HTMLWriter::generate(gdioutput &gdi, ostream &fout, const wstring &title, const wstring &contentDescription, bool respectPageBreak, const int nRows, const int numCol, const int interval, const int marginPercent, double scale) const { int w, h; gdi.getTargetDimension(w, h); ImageWriter imgWriter(L"", false); string meos = "MeOS: " + gdioutput::toUTF8(getMeosCompectVersion()) + ""; int margin = (w * marginPercent) / 100; int height = nRows * gdi.getLineHeight(); bool infPage = false; if (nRows == 0) { infPage = true; height = gdi.getPageY()/numCol; } PageInfo pageInfo; pageInfo.topMargin = 20; pageInfo.scaleX = 1.0f; pageInfo.scaleY = 1.0f; pageInfo.leftMargin = 20; pageInfo.bottomMargin = 30; pageInfo.pageY = float(height - margin); pageInfo.printHeader = false; pageInfo.yMM2PrintC = pageInfo.xMM2PrintC = 1; pageInfo.xMM2PrintK = 0; pageInfo.yMM2PrintK = 0; list rectangles; vector pages; pageInfo.renderPages(gdi.getTL(), rectangles, false, respectPageBreak || infPage, pages); int numChapter = 0; for (auto &pi : pages) if (pi.startChapter) numChapter++; if (infPage && pages.size() > size_t(numCol)) { bool respectChapter = numChapter == numCol; // If the number of chapters (linked lists) equals number of columns, respec these. vector pagesOut; bool startPage = true; int ydiff = 0; for (auto &p : pages) { if (p.text.empty()) continue; if (respectChapter) startPage = p.startChapter; else if (!pagesOut.empty() && pagesOut.back().text.back().yp + p.text.back().yp / 4 > height) startPage = true; if (startPage && pagesOut.size() < size_t(numCol)) { pagesOut.push_back(move(p)); startPage = false; ydiff = int(pagesOut.back().text.back().yp); } else { for (auto &t : p.text) { pagesOut.back().text.push_back(move(t)); pagesOut.back().text.back().yp += ydiff; } ydiff = int(pagesOut.back().text.back().yp); } } pages.swap(pagesOut); } string output = head; replaceAll(output, "@D", gdioutput::toUTF8(encodeXML(contentDescription))); replaceAll(output, "@T", gdioutput::toUTF8(encodeXML(title))); replaceAll(output, "@M", meos); map, pair> styles; { stringstream sout; generateStyles(gdi, sout, scale, false, gdi.getTL(), styles); replaceAll(output, "@S", sout.str()); } int nPage = (pages.size() + numCol - 1) / numCol; replaceAll(output, "@N", itos(nPage)); fout << output; int ipCounter = 1; int opCounter = 1; for (size_t pix = 0; pix < pages.size();) { string innerpageoutput; for (int ip = 0; ip < numCol; ip++) { if (pages.size() == pix) break; if (ip > 0) { // Separator output = separator; replaceAll(output, "@P", itos(ipCounter)); replaceAll(output, "@L", itos((ip * 100) / numCol)); innerpageoutput += output; } auto &p = pages[pix++]; stringstream sout; double yscale = 1.3 * scale; double xscale = 1.2 * scale; int offsetY = 0, offsetX = 0; formatTL, InterpPrintTextInfo>(sout, imgWriter, styles, p.text, yscale, xscale, offsetY, offsetX); output = innerpage; replaceAll(output, "@P", itos(ipCounter++)); replaceAll(output, "@L", itos((ip * 100) / numCol)); replaceAll(output, "@C", sout.str()); replaceAll(output, "@M", meos); innerpageoutput += output; } string outeroutput = outerpage; replaceAll(outeroutput, "@P", itos(opCounter++)); replaceAll(outeroutput, "@C", innerpageoutput); replaceAll(output, "@M", meos); replaceAll(output, "@N", itos(nPage)); fout << outeroutput << endl; } assert(opCounter - 1 == nPage); output = end; replaceAll(output, "@N", itos(opCounter - 1)); replaceAll(output, "@I", itos(numCol)); replaceAll(output, "@T", itos(interval)); replaceAll(output, "@M", meos); fout << output; } void HTMLWriter::write(gdioutput &gdi, const wstring &file, const wstring &title, const wstring &contentsDescription, bool respectPageBreak, const string &typeTag, int refresh, int rows, int cols, int time_ms, int margin, double scale) { checkWriteAccess(file); ofstream fout(file.c_str()); wchar_t drive[20]; wchar_t dir[MAX_PATH]; wchar_t name[MAX_PATH]; wchar_t ext[MAX_PATH]; _wsplitpath_s(file.c_str(), drive, dir, name, ext); wstring path = wstring(drive) + dir; write(gdi, fout, title, true, path, contentsDescription, respectPageBreak, typeTag, refresh, rows, cols, time_ms, margin, scale); } void HTMLWriter::write(gdioutput &gdi, ostream &fout, const wstring &title, bool includeImages, const wstring& imageDirectoryDestination, const wstring &contentsDescription, bool respectPageBreak, const string &typeTag, int refresh, int rows, int cols, int time_ms, int margin, double scale) { if (typeTag == "table") writeTableHTML(gdi, fout, title, includeImages, imageDirectoryDestination, false, refresh, scale); else if (typeTag == "free") { writeHTML(gdi, fout, title, includeImages, imageDirectoryDestination, refresh, scale); } else { /* auto res = tCache.find(typeTag); if (res == tCache.end()) { vector htmlTmpl; HTMLWriter::enumTemplates(TemplateType::List, htmlTmpl); int ix = -1; for (size_t k = 0; k < htmlTmpl.size(); k++) { if (htmlTmpl[k].tag == typeTag) { ix = k; break; } } if (ix == -1) throw std::exception("Internal error"); shared_ptr tmpl = make_shared(); tmpl->read(htmlTmpl[ix].file); vector tagName; split(tmpl->info, "@", tagName); if (tagName.size() == 2) tCache[tagName[0]] = tmpl; tmpl->generate(gdi, fout, title, contentsDescription, respectPageBreak, rows, cols, time_ms, margin, scale); } else { res->second->generate(gdi, fout, title, contentsDescription, respectPageBreak, rows, cols, time_ms, margin, scale); }*/ getWriter(TemplateType::List, typeTag).generate(gdi, fout, title, contentsDescription, respectPageBreak, rows, cols, time_ms, margin, scale); } } void HTMLWriter::write(gdioutput &gdi, const wstring &file, const wstring &title, int refresh, oListParam ¶m, const oEvent &oe) { write(gdi, file, title, param.getContentsDescriptor(oe), param.pageBreak, param.htmlTypeTag, refresh != 0 ? refresh : param.timePerPage / 1000, param.htmlRows, param.nColumns, param.timePerPage, param.margin, param.htmlScale); } void HTMLWriter::write(gdioutput& gdi, ostream& fout, const wstring& title, int refresh, oListParam& param, const oEvent& oe) { write(gdi, fout, title, true, L"", param.getContentsDescriptor(oe), param.pageBreak, param.htmlTypeTag, refresh != 0 ? refresh : param.timePerPage / 1000, param.htmlRows, param.nColumns, param.timePerPage, param.margin, param.htmlScale); } void HTMLWriter::getPage(const oEvent &oe, string &out) const { out = page; } void HTMLWriter::ImageWriter::write(ostream& fout, const string& xp, const string& yp, const wstring& img, int width, int height) { if (!writeImages) { if (xp.empty()) fout << " "; } else { if (img.empty() || img[0] != 'L') throw meosException("Unsupported image"); uint64_t imgId = _wcstoui64(img.c_str() + 1, nullptr, 10); if (!savedFiles.count(imgId)) { if (!destination.empty()) { auto& data = image.getRawData(imgId); wstring d = destination + img + L".png"; ofstream out(d, ofstream::out | ofstream::binary); out.write((const char *)data.data(), data.size()); savedFiles[imgId] = "L" + itos(imgId) + ".png"; } else { savedFiles[imgId] = "/meos?image=ID" + itos(imgId) + ".png"; } } string style; if (xp.size() > 0) style = " style=\"position:absolute;left:" + xp + "px;top:" + yp + "px\""; fout << ""; } }