Files
core/DjVuFile/DjVuFileImplementation.cpp
Kulikova Svetlana ea6c30e2bd common script
2021-11-15 18:55:05 +03:00

1594 lines
47 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2019
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "DjVuFileImplementation.h"
#include "../DesktopEditor/common/File.h"
#include "../DesktopEditor/common/Directory.h"
#include "../PdfWriter/PdfRenderer.h"
#include "../DesktopEditor/graphics/pro/Fonts.h"
#include "../DesktopEditor/graphics/pro/Graphics.h"
#include "../DesktopEditor/graphics/pro/Image.h"
#include "../DesktopEditor/common/StringExt.h"
#define VER_DPI 96
#define HOR_DPI 96
#include <vector>
#ifdef BUILDING_WASM_MODULE
#include "../DesktopEditor/graphics/pro/js/wasm/src/serialize.h"
#endif
namespace NSDjvu
{
static GUTF8String MakeUTF8String(const std::wstring& wsText)
{
std::string sText = NSFile::CUtf8Converter::GetUtf8StringFromUnicode(wsText);
GUTF8String utf8String(sText.c_str());
return utf8String;
}
static std::string MakeCString(GUTF8String& strText)
{
std::string sString(strText.getbuf());
return sString;
}
static int GetInteger(const std::wstring& wsString)
{
if (wsString.size() < 1)
return 0;
try
{
return std::stoi(wsString);
}
catch (...)
{
}
try
{
return static_cast<int>(std::stol(wsString));
}
catch (...)
{
return 0;
}
}
}
CDjVuFileImplementation::CDjVuFileImplementation(NSFonts::IApplicationFonts* pFonts)
{
m_pDoc = NULL;
#ifndef BUILDING_WASM_MODULE
std::wstring wsTempPath = NSFile::CFileBinary::GetTempPath();
wsTempPath += L"DJVU\\";
m_wsTempDirectory = wsTempPath;
NSDirectory::CreateDirectory(m_wsTempDirectory);
#endif
m_pApplicationFonts = pFonts;
}
CDjVuFileImplementation::~CDjVuFileImplementation()
{
#ifndef BUILDING_WASM_MODULE
NSDirectory::DeleteDirectory(m_wsTempDirectory);
#endif
}
bool CDjVuFileImplementation::LoadFromFile(const std::wstring& wsSrcFileName, const std::wstring& wsXMLOptions)
{
m_pDoc = NULL;
try
{
GUTF8String utf8;
GURL url = GURL::Filename::UTF8(NSDjvu::MakeUTF8String(wsSrcFileName));
m_pDoc = DjVuDocument::create(url);
m_pDoc->wait_get_pages_num();
}
catch (...)
{
return false;
}
return true;
}
bool CDjVuFileImplementation::LoadFromMemory(BYTE* data, DWORD length, const std::wstring& wsXmlOptions)
{
m_pDoc = NULL;
try
{
GP<ByteStream> stream = ByteStream::create(data, (size_t)length);
m_pDoc = DjVuDocument::create(stream);
m_pDoc->wait_get_pages_num();
}
catch (...)
{
return false;
}
return true;
}
void CDjVuFileImplementation::Close()
{
}
std::wstring CDjVuFileImplementation::GetTempDirectory() const
{
return m_wsTempDirectory;
}
void CDjVuFileImplementation::SetTempDirectory(const std::wstring& wsDirectory)
{
NSDirectory::DeleteDirectory(m_wsTempDirectory);
m_wsTempDirectory = wsDirectory;
m_wsTempDirectory += L"\\DJVU\\";
NSDirectory::CreateDirectory(m_wsTempDirectory);
}
int CDjVuFileImplementation::GetPagesCount() const
{
if (!m_pDoc)
return 0;
return m_pDoc->get_pages_num();
}
void CDjVuFileImplementation::GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY) const
{
if (!m_pDoc)
{
*pdWidth = 0;
*pdHeight = 0;
*pdDpiX = 96;
*pdDpiY = 96;
}
#if 0
GP<DjVuImage> pPage = m_pDoc->get_page(nPageIndex);
pPage->wait_for_complete_decode();
pPage->set_rotate(0);
*pdWidth = pPage->get_real_width();
*pdHeight = pPage->get_real_height();
*pdDpiX = pPage->get_dpi();
*pdDpiY = pPage->get_dpi();
#endif
int nW = 0;
int nH = 0;
int nDpi = 0;
m_pDoc->ReadPageInfo(nPageIndex, nW, nH, nDpi);
*pdWidth = nW;
*pdHeight = nH;
*pdDpiX = nDpi;
*pdDpiY = nDpi;
}
void CDjVuFileImplementation::DrawPageOnRenderer(IRenderer* pRenderer, int nPageIndex, bool* pBreak)
{
if (!m_pDoc)
return;
try
{
GP<DjVuImage> pPage = m_pDoc->get_page(nPageIndex);
pPage->wait_for_complete_decode();
pPage->set_rotate(0);
long lRendererType = c_nUnknownRenderer;
pRenderer->get_Type(&lRendererType);
if (false)//c_nGrRenderer == lRendererType)
{
CreateGrFrame(pRenderer, pPage, pBreak);
}
#ifndef BUILDING_WASM_MODULE
else if (c_nPDFWriter == lRendererType)
{
XmlUtils::CXmlNode oText = ParseText(pPage);
CreatePdfFrame(pRenderer, pPage, nPageIndex, oText);
}
#endif
else
{
XmlUtils::CXmlNode oText = ParseText(pPage);
CreateFrame(pRenderer, pPage, nPageIndex, oText);
}
}
catch (...)
{
// белая страница
}
}
BYTE* CDjVuFileImplementation::ConvertToPixels(int nPageIndex, const int& nRasterW, const int& nRasterH, bool bIsFlip)
{
if (!m_pApplicationFonts)
return NULL;
NSFonts::IFontManager *pFontManager = m_pApplicationFonts->GenerateFontManager();
NSFonts::IFontsCache* pFontCache = NSFonts::NSFontCache::Create();
pFontCache->SetStreams(m_pApplicationFonts->GetStreams());
pFontManager->SetOwnerCache(pFontCache);
NSGraphics::IGraphicsRenderer* pRenderer = NSGraphics::Create();
pRenderer->SetFontManager(pFontManager);
double dPageDpiX;
double dWidth, dHeight;
GetPageInfo(nPageIndex, &dWidth, &dHeight, &dPageDpiX, &dPageDpiX);
int nWidth = (nRasterW > 0) ? nRasterW : ((int)dWidth * 96 / dPageDpiX);
int nHeight = (nRasterH > 0) ? nRasterH : ((int)dHeight * 96 / dPageDpiX);
BYTE* pBgraData = new BYTE[nWidth * nHeight * 4];
if (!pBgraData)
return NULL;
memset(pBgraData, 0xff, nWidth * nHeight * 4);
CBgraFrame oFrame;
oFrame.put_Data(pBgraData);
oFrame.put_Width(nWidth);
oFrame.put_Height(nHeight);
oFrame.put_Stride((bIsFlip ? 4 : -4) * nWidth);
pRenderer->CreateFromBgraFrame(&oFrame);
pRenderer->SetSwapRGB(true);
pRenderer->put_Width(dWidth);
pRenderer->put_Height(dHeight);
bool bBreak = false;
DrawPageOnRenderer(pRenderer, nPageIndex, &bBreak);
RELEASEINTERFACE(pFontManager);
RELEASEOBJECT(pRenderer);
oFrame.ClearNoAttack();
return pBgraData;
}
void CDjVuFileImplementation::ConvertToRaster(int nPageIndex, const std::wstring& wsDstPath, int nImageType, const int& nRasterW, const int& nRasterH)
{
if (!m_pApplicationFonts)
return;
NSFonts::IFontManager *pFontManager = m_pApplicationFonts->GenerateFontManager();
NSFonts::IFontsCache* pFontCache = NSFonts::NSFontCache::Create();
pFontCache->SetStreams(m_pApplicationFonts->GetStreams());
pFontManager->SetOwnerCache(pFontCache);
NSGraphics::IGraphicsRenderer* pRenderer = NSGraphics::Create();
pRenderer->SetFontManager(pFontManager);
double dPageDpiX, dPageDpiY;
double dWidth, dHeight;
GetPageInfo(nPageIndex, &dWidth, &dHeight, &dPageDpiX, &dPageDpiX);
int nWidth = (nRasterW > 0) ? nRasterW : ((int)dWidth * 96 / dPageDpiX);
int nHeight = (nRasterH > 0) ? nRasterH : ((int)dHeight * 96 / dPageDpiX);
BYTE* pBgraData = new BYTE[nWidth * nHeight * 4];
if (!pBgraData)
return;
memset(pBgraData, 0xff, nWidth * nHeight * 4);
CBgraFrame oFrame;
oFrame.put_Data(pBgraData);
oFrame.put_Width(nWidth);
oFrame.put_Height(nHeight);
oFrame.put_Stride(-4 * nWidth);
pRenderer->CreateFromBgraFrame(&oFrame);
pRenderer->SetSwapRGB(false);
pRenderer->put_Width(dWidth);
pRenderer->put_Height(dHeight);
bool bBreak = false;
DrawPageOnRenderer(pRenderer, nPageIndex, &bBreak);
oFrame.SaveFile(wsDstPath, nImageType);
RELEASEINTERFACE(pFontManager);
RELEASEOBJECT(pRenderer);
}
void CDjVuFileImplementation::ConvertToPdf(const std::wstring& wsDstPath)
{
CPdfRenderer oPdf(m_pApplicationFonts);
bool bBreak = false;
for (int nPageIndex = 0, nPagesCount = GetPagesCount(); nPageIndex < nPagesCount; nPageIndex++)
{
oPdf.NewPage();
double dPageDpiX, dPageDpiY;
double dWidth, dHeight;
GetPageInfo(nPageIndex, &dWidth, &dHeight, &dPageDpiX, &dPageDpiY);
dWidth *= 25.4 / dPageDpiX;
dHeight *= 25.4 / dPageDpiY;
oPdf.put_Width(dWidth);
oPdf.put_Height(dHeight);
DrawPageOnRenderer(&oPdf, nPageIndex, &bBreak);
//#ifdef _DEBUG
printf("%d of %d pages\n", nPageIndex + 1, nPagesCount);
//#endif
}
oPdf.SaveToFile(wsDstPath);
}
#ifdef BUILDING_WASM_MODULE
void getBookmars(const GP<DjVmNav>& nav, int& pos, int count, NSWasm::CData& out, int level)
{
while (count > 0 && pos < nav->getBookMarkCount())
{
GP<DjVmNav::DjVuBookMark> gpBookMark;
nav->getBookMark(gpBookMark, pos++);
GUTF8String str = gpBookMark->url;
int endpos;
DWORD nPage = str.toULong(1, endpos) - 1;
if (endpos == (int)str.length())
{
out.AddInt(nPage);
out.AddInt(level);
out.AddDouble(0.0);
GUTF8String description = gpBookMark->displayname;
out.WriteString((BYTE*)description.getbuf(), description.length());
}
getBookmars(nav, pos, gpBookMark->count, out, level + 1);
count--;
}
}
BYTE* CDjVuFileImplementation::GetStructure()
{
GP<DjVmNav> nav = m_pDoc->get_djvm_nav();
if (!nav)
return NULL;
int pos = 0;
int count = nav->getBookMarkCount();
if (count <= 0)
return NULL;
NSWasm::CData oRes;
oRes.SkipLen();
getBookmars(nav, pos, count, oRes, 1);
oRes.WriteLen();
BYTE* bRes = oRes.GetBuffer();
oRes.ClearWithoutAttack();
return bRes;
}
BYTE* CDjVuFileImplementation::GetPageGlyphs(int nPageIndex)
{
return NULL;
try
{
GP<DjVuImage> pPage = m_pDoc->get_page(nPageIndex);
const GP<DjVuText> text(DjVuText::create());
const GP<ByteStream> text_str(pPage->get_text());
if (!text_str)
return NULL;
text->decode(text_str);
GUTF8String pageText = text->get_xmlText(pPage->get_height());
XmlUtils::CXmlNode hiddenText;
XmlUtils::CXmlNode pageColumn;
XmlUtils::CXmlNode region;
hiddenText.FromXmlStringA(NSDjvu::MakeCString(pageText));
hiddenText.GetNode(L"PAGECOLUMN", pageColumn);
pageColumn.GetNode(L"REGION", region);
NSWasm::CData oRes;
oRes.SkipLen();
XmlUtils::CXmlNodes oParagraphsNodes;
region.GetNodes(L"PARAGRAPH", oParagraphsNodes);
for (int nParagraphIndex = 0; nParagraphIndex < oParagraphsNodes.GetCount(); nParagraphIndex++)
{
XmlUtils::CXmlNode oParagraphNode;
oParagraphsNodes.GetAt(nParagraphIndex, oParagraphNode);
XmlUtils::CXmlNodes oLinesNodes;
oParagraphNode.GetNodes(L"LINE", oLinesNodes);
for (int nLineIndex = 0; nLineIndex < oLinesNodes.GetCount(); nLineIndex++)
{
XmlUtils::CXmlNode oLineNode;
oLinesNodes.GetAt(nLineIndex, oLineNode);
XmlUtils::CXmlNodes oWordsNodes;
oLineNode.GetNodes(L"WORD", oWordsNodes);
for (int nWordIndex = 0; nWordIndex < oWordsNodes.GetCount(); nWordIndex++)
{
XmlUtils::CXmlNode oWordNode;
oWordsNodes.GetAt(nWordIndex, oWordNode);
std::wstring csWord = oWordNode.GetText();
std::wstring csCoords = oWordNode.GetAttribute(L"coords");
double arrCoords[4];
ParseCoords(csCoords, arrCoords, 1);
std::string sText = U_TO_UTF8(csWord);
oRes.WriteString((BYTE*)sText.c_str(), sText.length());
oRes.AddDouble(arrCoords[0]);
oRes.AddDouble(arrCoords[3]);
oRes.AddDouble(arrCoords[2] - arrCoords[0]);
oRes.AddDouble(arrCoords[1] - arrCoords[3]);
}
}
}
oRes.WriteLen();
BYTE* res = oRes.GetBuffer();
oRes.ClearWithoutAttack();
return res;
}
catch (...) {}
return NULL;
}
BYTE* CDjVuFileImplementation::GetPageLinks (int nPageIndex)
{
double dPageDpiX, dPageDpiY;
double dWidth, dHeight;
GetPageInfo(nPageIndex, &dWidth, &dHeight, &dPageDpiX, &dPageDpiY);
try
{
GP<DjVuImage> pPage = m_pDoc->get_page(nPageIndex);
pPage->wait_for_complete_decode();
GP<DjVuAnno> pAnno = pPage->get_decoded_anno();
if (!pAnno)
return NULL;
GPList<GMapArea> map_areas = pAnno->ant->map_areas;
NSWasm::CData oRes;
oRes.SkipLen();
for (GPosition pos(map_areas); pos; ++pos)
{
GUTF8String str = map_areas[pos]->url;
oRes.WriteString((BYTE*)str.getbuf(), str.length());
// Верхний левый угол
double x = map_areas[pos]->get_xmin();
double y = dHeight - map_areas[pos]->get_ymax();
oRes.AddDouble(0.0);
oRes.AddDouble(x);
oRes.AddDouble(y);
oRes.AddDouble(map_areas[pos]->get_xmax() - x);
oRes.AddDouble(map_areas[pos]->get_ymax() - map_areas[pos]->get_ymin());
}
oRes.WriteLen();
BYTE* res = oRes.GetBuffer();
oRes.ClearWithoutAttack();
return res;
}
catch (...) {}
return NULL;
}
void CDjVuFileImplementation::GetGlyphs(IRenderer* m_pRenderer, const std::wstring& bsUnicodeText, unsigned int* pGids, double x, double y)
{
// m_pInternal->GetUnicodes(bsUnicodeText);
int nLen = (int)bsUnicodeText.length();
int* pTempUnicodes = new int[nLen];
int nTempUnicodesLen = 0;
const wchar_t* pWchars = bsUnicodeText.c_str();
if (sizeof(wchar_t) == 2)
{
for (int i = 0; i < nLen; i++)
{
int code = (int)pWchars[i];
if (code >= 0xD800 && code <= 0xDFFF && (i + 1) < nLen)
code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & pWchars[++i]));
pTempUnicodes[nTempUnicodesLen++] = code;
}
}
else
for (int i = 0; i < nLen; i++)
pTempUnicodes[nTempUnicodesLen++] = (int)pWchars[i];
// m_pInternal->m_oWriter.WriteText(pTempUnicodes, (const int*)pGids, nTempUnicodesLen, x, y, w, h, m_pInternal->m_bIsChangedFontParamBetweenDrawText);
bool bIsDumpFont = false;
std::wstring sCurrentFontName; double dFontSize;
m_pRenderer->get_FontName(&sCurrentFontName);
m_pRenderer->get_FontSize(&dFontSize);
int nCurrentFont = 0;
if ((nCurrentFont != m_lCurrentFont) || (dFontSize != m_dCurrentFontSize))
{
m_lCurrentFont = nCurrentFont;
m_dCurrentFontSize = dFontSize;
bIsDumpFont = true;
}
// m_oSmartText.CommandText(pTempUnicodes, (const int*)pGids, nTempUnicodesLen, x, y, w, h, bIsDumpFont, this);
// 1) сначала определяем точку отсчета и направление baseline
double _x1 = x;
double _y1 = y;
double _x2 = x + 1;
double _y2 = y;
double sx, shy, shx, sy, tx, ty, tmp;
m_pRenderer->GetTransform(&sx, &shy, &shx, &sy, &tx, &ty);
// m_pTransform->TransformPoint(_x1, _y1);
tmp = _x1;
_x1 = tmp * sx + _y1 * shx + tx;
_y1 = tmp * shy + _y1 * sy + ty;
// m_pTransform->TransformPoint(_x2, _y2);
tmp = _x2;
_x2 = tmp * sx + _y2 * shx + tx;
_y2 = tmp * shy + _y2 * sy + ty;
double _k = 0;
double _b = 0;
bool _isConstX = false;
if (fabs(_x1 - _x2) < 0.001)
{
_isConstX = true;
_b = _x1;
}
else
{
_k = (_y1 - _y2) / (_x1 - _x2);
_b = _y1 - _k * _x1;
}
double dAbsVec = sqrt((_x1 - _x2) * (_x1 - _x2) + (_y1 - _y2) * (_y1 - _y2));
if (dAbsVec == 0)
dAbsVec = 1;
LONG nCountChars = m_oLine.GetCountChars();
bool bIsNewLine = true;
if (0 != nCountChars)
{
if (_isConstX && m_oLine.m_bIsConstX && fabs(_b - m_oLine.m_dB) < 0.001)
bIsNewLine = false;
else if (!_isConstX && !m_oLine.m_bIsConstX && fabs(_k - m_oLine.m_dK) < 0.001 && fabs(_b - m_oLine.m_dB) < 0.001)
bIsNewLine = false;
}
if (bIsNewLine && (nCountChars != 0))
{
// не совпала baseline. поэтому просто скидываем линию в поток
DumpLine();
}
// теперь нужно определить сдвиг по baseline относительно destination точки
nCountChars = m_oLine.GetCountChars();
double dOffsetX = 0;
if (nCountChars == 0)
{
m_oLine.m_bIsConstX = _isConstX;
m_oLine.m_dK = _k;
m_oLine.m_dB = _b;
m_oLine.m_dX = _x1;
m_oLine.m_dY = _y1;
m_oLine.m_ex = (_x2 - _x1) / dAbsVec;
m_oLine.m_ey = (_y2 - _y1) / dAbsVec;
m_oLine.m_dEndX = _x1;
m_oLine.m_dEndY = _y1;
}
else
{
double _sx = _x1 - m_oLine.m_dEndX;
double _sy = _y1 - m_oLine.m_dEndY;
double len = sqrt(_sx * _sx + _sy * _sy);
if (_sx * m_oLine.m_ex >= 0 && _sy * m_oLine.m_ey >= 0)
{
// продолжаем линию
dOffsetX = len;
// теперь посмотрим, может быть нужно вставить пробел??
NSWasm::CHChar* pLastChar = m_oLine.GetTail();
if (dOffsetX > (pLastChar->width + 0.5))
{
// вставляем пробел. Пробел у нас будет не совсем пробел. А специфический
NSWasm::CHChar* pSpaceChar = m_oLine.AddTail();
pSpaceChar->x = pLastChar->width;
pSpaceChar->width = dOffsetX - pLastChar->width;
pSpaceChar->unicode = 0xFFFF;
pSpaceChar->gid = 0xFFFF;
dOffsetX -= pLastChar->width;
m_oMeta.WriteBYTE(0);
}
}
else
{
// буква сдвинута влево относительно предыдущей буквы
// на такую ситуацию реагируем просто - просто начинаем новую линию,
// предварительно сбросив старую
DumpLine();
m_oLine.m_bIsConstX = _isConstX;
m_oLine.m_dX = _x1;
m_oLine.m_dY = _y1;
m_oLine.m_dK = _k;
m_oLine.m_dB = _b;
m_oLine.m_ex = (_x2 - _x1) / dAbsVec;
m_oLine.m_ey = (_y2 - _y1) / dAbsVec;
}
m_oLine.m_dEndX = _x1;
m_oLine.m_dEndY = _y1;
}
// смотрим, совпадает ли главная часть матрицы.
bool bIsTransform = !(fabs(m_pLastTransform.sx() - sx) < 0.001 &&
fabs(m_pLastTransform.sy() - sy) < 0.001 &&
fabs(m_pLastTransform.shx() - shx) < 0.001 &&
fabs(m_pLastTransform.shy() - shy) < 0.001);
if (bIsTransform)
bIsDumpFont = true;
LONG nColor1, nAlpha1;
m_pRenderer->get_BrushColor1(&nColor1);
m_pRenderer->get_BrushAlpha1(&nAlpha1);
bool bIsColor = ((nColor1 != m_nLastBrushColor1) || (nAlpha1 != m_nLastBrushAlpha1));
BYTE nLenMetaCommands = 0;
if (bIsColor)
nLenMetaCommands += 5;
if (bIsTransform)
nLenMetaCommands += 17;
if (bIsDumpFont)
nLenMetaCommands += 13;
m_oMeta.WriteBYTE(nLenMetaCommands);
double _dumpSize = dFontSize;
double _dumpMtx[4];
_dumpMtx[0] = sx;
_dumpMtx[1] = shy;
_dumpMtx[2] = shx;
_dumpMtx[3] = sy;
double dTextScale = std::min(sqrt(_dumpMtx[2] * _dumpMtx[2] + _dumpMtx[3] * _dumpMtx[3]),
sqrt(_dumpMtx[0] * _dumpMtx[0] + _dumpMtx[1] * _dumpMtx[1]));
if ((_dumpSize < 0.1 && dTextScale > 10) || (_dumpSize > 10 && dTextScale < 0.1))
{
_dumpSize *= dTextScale;
_dumpMtx[0] /= dTextScale;
_dumpMtx[1] /= dTextScale;
_dumpMtx[2] /= dTextScale;
_dumpMtx[3] /= dTextScale;
}
if (bIsDumpFont)
{
LONG nFontStyle;
m_pRenderer->get_FontStyle(&nFontStyle);
m_oMeta.WriteBYTE(41); // CMetafile::ctFontName
m_oMeta.AddInt(nCurrentFont);
m_oMeta.AddInt(nFontStyle);
m_oMeta.WriteDouble(_dumpSize);
}
if (bIsTransform)
{
m_pLastTransform.SetElements(sx, shy, shx, sy);
m_oLine.m_bIsSetUpTransform = true;
m_oLine.m_sx = sx;
m_oLine.m_shx = shx;
m_oLine.m_shy = shy;
m_oLine.m_sy = sy;
m_oMeta.WriteBYTE(161); // CMetafile::ctCommandTextTransform
m_oMeta.WriteDouble(_dumpMtx[0]);
m_oMeta.WriteDouble(_dumpMtx[1]);
m_oMeta.WriteDouble(_dumpMtx[2]);
m_oMeta.WriteDouble(_dumpMtx[3]);
}
if (bIsColor)
{
m_nLastBrushColor1 = nColor1;
m_nLastBrushAlpha1 = nAlpha1;
m_oMeta.WriteBYTE(22); // CMetafile::ctBrushColor1
LONG lBGR = nColor1;
m_oMeta.WriteBYTE((BYTE)(lBGR & 0xFF));
m_oMeta.WriteBYTE((BYTE)((lBGR >> 8) & 0xFF));
m_oMeta.WriteBYTE((BYTE)((lBGR >> 16) & 0xFF));
m_oMeta.WriteBYTE((BYTE)nAlpha1);
}
NSFonts::IFontManager *m_pFontManager = ((NSGraphics::IGraphicsRenderer*)m_pRenderer)->GetFontManager();
// все, baseline установлен. теперь просто продолжаем линию
if (bIsDumpFont)
{
m_pFontManager->LoadFontFromFile(sCurrentFontName, 0, dFontSize, 72.0, 72.0);
m_pFontManager->AfterLoad();
}
double dKoef = dFontSize * 25.4 / (72 * abs(m_pFontManager->GetUnitsPerEm()));
double dAscender = abs(m_pFontManager->GetAscender()) * dKoef * dAbsVec;
double dDescender = abs(m_pFontManager->GetDescender()) * dKoef * dAbsVec;
if (m_oLine.m_dAscent < dAscender)
m_oLine.m_dAscent = dAscender;
if (m_oLine.m_dDescent < dDescender)
m_oLine.m_dDescent = dDescender;
double dPlusOffset = 0;
int* input = NULL;
if (pGids)
{
input = (int*)pGids;
m_pFontManager->SetStringGID(TRUE);
}
else
{
input = pTempUnicodes;
m_pFontManager->SetStringGID(FALSE);
}
for (int i = 0; i < nTempUnicodesLen; i++)
{
// double dW = m_oFontManager.MeasureString((const unsigned int*)(input + lIndex), 1, 0, 0, dBoxX, dBoxY, dBoxW, dBoxH);
m_pFontManager->LoadString1((unsigned int*)(input + i), 1, 0, 0);
TBBox _box = m_pFontManager->MeasureString2();
double dBoxW = abs(_box.fMaxX - _box.fMinX) * 25.4 / 72.0;
NSWasm::CHChar* pChar = m_oLine.AddTail();
pChar->unicode = pTempUnicodes[i];
pChar->gid = pGids ? pGids[i] : 0xFFFF;
pChar->x = dOffsetX;
if (i != 0)
dPlusOffset += dOffsetX;
dOffsetX = dBoxW;
pChar->width = dBoxW * dAbsVec;
if (i != 0)
m_oMeta.WriteBYTE(0);
if (i == (nTempUnicodesLen - 1))
{
m_oLine.m_dEndX += dPlusOffset * m_oLine.m_ex;
m_oLine.m_dEndY += dPlusOffset * m_oLine.m_ey;
}
}
RELEASEARRAYOBJECTS(pTempUnicodes);
}
void CDjVuFileImplementation::DumpLine()
{
if (m_oLine.m_bIsSetUpTransform)
{
// выставится трансформ!!!
// cравнивать нужно с ним!!!
m_pLastTransform.SetElements(m_oLine.m_sx, m_oLine.m_shy, m_oLine.m_shx, m_oLine.m_sy);
}
// скидываем линию в поток pMeta
BYTE mask = 0;
if (fabs(m_oLine.m_ex - 1.0) < 0.001 && fabs(m_oLine.m_ey) < 0.001)
mask |= 0x01;
LONG lCountSpaces = 0;
LONG lCountSymbols = 0;
LONG lCountWords = 0;
bool bIsLastSymbol = false;
bool bIsGidExist = false;
LONG nCount = m_oLine.GetCountChars();
for (LONG i = 0; i < nCount; i++)
{
NSWasm::CHChar* pChar = &m_oLine.m_pChars[i];
if (pChar->gid != 0xFFFF)
{
mask |= 0x02;
bIsGidExist = true;
}
if (0xFFFF == pChar->unicode || L' ' == pChar->unicode || L'\t' == pChar->unicode)
{
lCountSpaces++;
if (bIsLastSymbol)
{
bIsLastSymbol = false;
lCountWords++;
}
}
else
{
bIsLastSymbol = true;
lCountSymbols++;
}
}
if (bIsLastSymbol)
lCountWords++;
if (0 == nCount)
{
m_oLine.Clear();
m_oMeta.ClearNoAttack();
return;
}
if (nCount > 1)
mask |= 0x04;
m_pPageMeta.WriteBYTE(160); // CMetafile::ctCommandTextLine
m_pPageMeta.WriteBYTE(mask);
m_pPageMeta.WriteDouble(m_oLine.m_dX);
m_pPageMeta.WriteDouble(m_oLine.m_dY);
if ((mask & 0x01) == 0)
{
m_pPageMeta.WriteDouble(m_oLine.m_ex);
m_pPageMeta.WriteDouble(m_oLine.m_ey);
}
m_pPageMeta.WriteDouble(m_oLine.m_dAscent);
m_pPageMeta.WriteDouble(m_oLine.m_dDescent);
LONG _position = 0;
if (nCount > 1)
{
_position = m_pPageMeta.GetSize();
m_pPageMeta.AddInt(0);
}
BYTE* pBufferMeta = m_oMeta.GetBuffer();
double dWidthLine = 0;
double dCurrentGlyphLineOffset = 0;
for (LONG lIndexChar = 0; lIndexChar < nCount; lIndexChar++)
{
NSWasm::CHChar* pChar = &m_oLine.m_pChars[lIndexChar];
// все настроки буквы (m_oMeta)
BYTE lLen = *pBufferMeta;
pBufferMeta++;
if (lLen > 0)
m_pPageMeta.Write(pBufferMeta, lLen);
pBufferMeta += lLen;
// смещение относительно предыдущей буквы (у всех, кроме первой)
// юникодное значение
// гид (если bIsGidExist == true)
// ширина буквы
m_pPageMeta.WriteBYTE(80); // CMetafile::ctDrawText
if (lIndexChar)
m_pPageMeta.WriteDouble2(pChar->x);
m_pPageMeta.WriteWCHAR(pChar->unicode);
if (bIsGidExist)
m_pPageMeta.WriteUSHORT(pChar->gid);
m_pPageMeta.WriteDouble2(pChar->width);
if (lIndexChar)
dCurrentGlyphLineOffset += pChar->x;
if (lIndexChar == (nCount - 1))
dWidthLine = dCurrentGlyphLineOffset + pChar->width;
}
if (nCount > 1)
{
int* pWidthBuf = (int*)(m_pPageMeta.GetBuffer() + _position);
*pWidthBuf = (int)(dWidthLine * 10000);
}
m_oLine.Clear();
m_oMeta.ClearNoAttack();
m_pPageMeta.WriteBYTE(162); // CMetafile::ctCommandTextLineEnd
}
#endif
void CDjVuFileImplementation::CreateFrame(IRenderer* pRenderer, GP<DjVuImage>& pPage, int nPage, XmlUtils::CXmlNode& text)
{
int nWidth = pPage->get_real_width();
int nHeight = pPage->get_real_height();
int nDpi = pPage->get_dpi();
double dPixToMM = 25.4;
double dRendDpiX = 0;
double dRendDpiY = 0;
pRenderer->get_DpiX(&dRendDpiX);
pRenderer->get_DpiY(&dRendDpiY);
if (0 >= dRendDpiX)
dRendDpiX = 72.0;
if (0 >= dRendDpiY)
dRendDpiY = 72.0;
double dRendWidth = 0;
double dRendHeight = 0;
pRenderer->get_Width(&dRendWidth);
pRenderer->get_Height(&dRendHeight);
if (0 >= dRendWidth)
dRendWidth = 200;
if (0 >= dRendHeight)
dRendHeight = 300;
LONG lImageWidth = (LONG)(dRendDpiX * dRendWidth / dPixToMM);
LONG lImageHeight = (LONG)(dRendDpiY * dRendHeight / dPixToMM);
long lRendererType = c_nUnknownRenderer;
pRenderer->get_Type(&lRendererType);
if (c_nPDFWriter == lRendererType)
{
lImageWidth = pPage->get_real_width();
lImageHeight = pPage->get_real_height();
}
else if (c_nHtmlRendrerer == lRendererType)
{
// TODO: Нужно реализовать функцию
// pRenderer->GetMaxImageSize();
//VARIANT var;
//renderer->GetAdditionalParam(L"MaxImageSize", &var);
//LONG lMaxWidth = var.lVal;
//if ((lImageWidth > lMaxWidth) || (lImageHeight > lMaxWidth))
//{
// double dAspect = (double)(lImageWidth) / lImageHeight;
// if (lImageWidth > lImageHeight)
// {
// lImageWidth = lMaxWidth;
// lImageHeight = (LONG)(lImageHeight / dAspect);
// }
// else
// {
// lImageHeight = lMaxWidth;
// lImageWidth = (LONG)(dAspect * lImageHeight);
// }
//}
}
BYTE* pBufferDst = new BYTE[4 * lImageHeight * lImageWidth];
if (!pBufferDst)
return;
Aggplus::CImage oImage;
oImage.Create(pBufferDst, lImageWidth, lImageHeight, 4 * lImageWidth);
if (pPage->is_legal_photo() || pPage->is_legal_compound())
{
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
BYTE* pBuffer = pBufferDst;
for (int j = lImageHeight - 1; j >= 0; --j)
{
GPixel* pLine = pImage->operator [](j);
for (int i = 0; i < lImageWidth; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
}
else if (pPage->is_legal_bilevel())
{
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GBitmap> pBitmap = pPage->get_bitmap(oRectAll, oRectAll, 4);
int nPaletteEntries = pBitmap->get_grays();
unsigned int* palette = new unsigned int[nPaletteEntries];
// Create palette for the bitmap
int color = 0xff0000;
int decrement = color / (nPaletteEntries - 1);
for (int i = 0; i < nPaletteEntries; ++i)
{
BYTE level = (BYTE)(color >> 16);
palette[i] = (0xFF000000 | level << 16 | level << 8 | level);
color -= decrement;
}
unsigned int* pBuffer = (unsigned int*)pBufferDst;
for (int j = lImageHeight - 1; j >= 0; --j)
{
BYTE* pLine = pBitmap->operator [](j);
for (int i = 0; i < lImageWidth; ++i, ++pBuffer, ++pLine)
{
if (*pLine < nPaletteEntries)
{
*pBuffer = palette[*pLine];
}
else
{
*pBuffer = palette[0];
}
}
}
RELEASEARRAYOBJECTS(palette);
}
else
{
// белый фрейм??
//memset(pBufferDst, 0xFF, 4 * lImageWidth * lImageHeight);
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
if (NULL != pImage)
{
BYTE* pBuffer = pBufferDst;
for (int j = lImageHeight - 1; j >= 0; --j)
{
GPixel* pLine = pImage->operator [](j);
for (int i = 0; i < lImageWidth; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
}
else
{
GP<GBitmap> pBitmap = pPage->get_bitmap(oRectAll, oRectAll, 4);
if (NULL != pBitmap)
{
int nPaletteEntries = pBitmap->get_grays();
unsigned int* palette = new unsigned int[nPaletteEntries];
// Create palette for the bitmap
int color = 0xff0000;
int decrement = color / (nPaletteEntries - 1);
for (int i = 0; i < nPaletteEntries; ++i)
{
BYTE level = (BYTE)(color >> 16);
palette[i] = (0xFF000000 | level << 16 | level << 8 | level);
color -= decrement;
}
unsigned int* pBuffer = (unsigned int*)pBufferDst;
for (int j = lImageHeight - 1; j >= 0; --j)
{
BYTE* pLine = pBitmap->operator [](j);
for (int i = 0; i < lImageWidth; ++i, ++pBuffer, ++pLine)
{
if (*pLine < nPaletteEntries)
{
*pBuffer = palette[*pLine];
}
else
{
*pBuffer = palette[0];
}
}
}
RELEASEARRAYOBJECTS(palette);
}
}
}
pRenderer->BeginCommand(c_nPageType);
if (c_nGrRenderer != lRendererType && c_nHtmlRendrerer != lRendererType && c_nHtmlRendrerer2 != lRendererType)
{
TextToRenderer(pRenderer, text, dPixToMM / nDpi);
}
#ifdef BUILDING_WASM_MODULE
TextToRenderer(pRenderer, text, dPixToMM / nDpi);
#endif
pRenderer->DrawImage((IGrObject*)&oImage, 0, 0, dRendWidth, dRendHeight);
pRenderer->EndCommand(c_nPageType);
}
void CDjVuFileImplementation::CreatePdfFrame(IRenderer* pRenderer, GP<DjVuImage>& pPage, int nPageIndex, XmlUtils::CXmlNode& oText)
{
double dPageDpiX, dPageDpiY;
double dWidth, dHeight;
GetPageInfo(nPageIndex, &dWidth, &dHeight, &dPageDpiX, &dPageDpiY);
dWidth *= 25.4 / dPageDpiX;
dHeight *= 25.4 / dPageDpiY;
pRenderer->BeginCommand(c_nPageType);
TextToRenderer(pRenderer, oText, 25.4 / pPage->get_dpi());
LONG lImageWidth = pPage->get_real_width();
LONG lImageHeight = pPage->get_real_height();
CPdfRenderer* pPdf = (CPdfRenderer*)pRenderer;
if (pPage->is_legal_photo())
{
BYTE* pBufferDst = new BYTE[4 * lImageHeight * lImageWidth];
if (!pBufferDst)
return;
Aggplus::CImage oImage;
oImage.Create(pBufferDst, lImageWidth, lImageHeight, 4 * lImageWidth);
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
BYTE* pBuffer = pBufferDst;
for (int j = lImageHeight - 1; j >= 0; --j)
{
GPixel* pLine = pImage->operator [](j);
for (int i = 0; i < lImageWidth; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
pRenderer->DrawImage((IGrObject*)&oImage, 0, 0, dWidth, dHeight);
}
else if (pPage->is_legal_compound())
{
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<IW44Image> pIW44Image = pPage->get_bg44();
if (NULL != pIW44Image)
{
int nBgWidth = pIW44Image->get_width();
int nBgHeight = pIW44Image->get_height();
GP<GPixmap> pBgImage = pIW44Image->get_pixmap();
if (NULL != pBgImage)
{
BYTE* pBgBuffer = new BYTE[4 * nBgWidth * nBgHeight];
if (!pBgBuffer)
return;
Aggplus::CImage oBgImage;
oBgImage.Create(pBgBuffer, nBgWidth, nBgHeight, 4 * nBgWidth);
BYTE* pBuffer = pBgBuffer;
for (int j = nBgHeight - 1; j >= 0; --j)
{
GPixel* pLine = pBgImage->operator [](j);
for (int i = 0; i < nBgWidth; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
pRenderer->DrawImage((IGrObject*)&oBgImage, 0, 0, dWidth, dHeight);
}
}
GP<GPixmap> pImage = pPage->get_fgpm();
if (NULL == pImage)
pImage = pPage->get_fg_pixmap(oRectAll);
if (NULL != pImage)
{
unsigned int unPixmapH = pImage->rows();
unsigned int unPixmapW = pImage->columns();
BYTE* pBufferDst = new BYTE[4 * unPixmapH * unPixmapW];
if (!pBufferDst)
return;
Aggplus::CImage oImage;
oImage.Create(pBufferDst, unPixmapW, unPixmapH, 4 * unPixmapW);
BYTE* pBuffer = pBufferDst;
for (int j = unPixmapH - 1; j >= 0; --j)
{
GPixel* pLine = pImage->operator [](j);
for (int i = 0; i < unPixmapW; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
GP<GBitmap> pBitmap = pPage->get_bitmap(oRectAll, oRectAll, 4);
NSImages::CPixJbig2 oPix;
if (oPix.Create(lImageWidth, lImageHeight, 1))
{
for (int nY = 0; nY < lImageHeight; nY++)
{
BYTE* pLine = pBitmap->operator [](nY);
for (int nX = 0; nX < lImageWidth; nX++, pLine++)
{
oPix.SetPixel(nX, lImageHeight - 1 - nY, *pLine);
}
}
pPdf->DrawImageWith1bppMask((IGrObject*)&oImage, &oPix, lImageWidth, lImageHeight, 0, 0, dWidth, dHeight);
oPix.Destroy();
}
}
}
else if (pPage->is_legal_bilevel())
{
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GBitmap> pBitmap = pPage->get_bitmap(oRectAll, oRectAll, 4);
NSImages::CPixJbig2 oPix;
if (oPix.Create(lImageWidth, lImageHeight, 1))
{
for (int nY = 0; nY < lImageHeight; nY++)
{
BYTE* pLine = pBitmap->operator [](nY);
for (int nX = 0; nX < lImageWidth; nX++, pLine++)
{
oPix.SetPixel(nX, lImageHeight - 1 - nY, *pLine);
}
}
pPdf->DrawImage1bpp(&oPix, lImageWidth, lImageHeight, 0, 0, dWidth, dHeight);
oPix.Destroy();
}
}
else
{
// белый фрейм??
//memset(pBufferDst, 0xFF, 4 * lImageWidth * lImageHeight);
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
if (NULL != pImage)
{
BYTE* pBufferDst = new BYTE[4 * lImageHeight * lImageWidth];
if (pBufferDst)
{
Aggplus::CImage oImage;
oImage.Create(pBufferDst, lImageWidth, lImageHeight, 4 * lImageWidth);
BYTE* pBuffer = pBufferDst;
for (int j = lImageHeight - 1; j >= 0; --j)
{
GPixel* pLine = pImage->operator [](j);
for (int i = 0; i < lImageWidth; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
pRenderer->DrawImage((IGrObject*)&oImage, 0, 0, dWidth, dHeight);
}
}
else
{
GP<GBitmap> pBitmap = pPage->get_bitmap(oRectAll, oRectAll, 4);
if (NULL != pBitmap)
{
int nPaletteEntries = pBitmap->get_grays();
if (nPaletteEntries <= 2)
{
NSImages::CPixJbig2 oPix;
if (oPix.Create(lImageWidth, lImageHeight, 1))
{
for (int nY = 0; nY < lImageHeight; nY++)
{
BYTE* pLine = pBitmap->operator [](nY);
for (int nX = 0; nX < lImageWidth; nX++, pLine++)
{
oPix.Create(nX, lImageHeight - 1 - nY, *pLine);
}
}
pPdf->DrawImage1bpp(&oPix, lImageWidth, lImageHeight, 0, 0, dWidth, dHeight);
oPix.Destroy();
}
}
else
{
BYTE* pBufferDst = new BYTE[4 * lImageHeight * lImageWidth];
if (!pBufferDst)
return;
Aggplus::CImage oImage;
oImage.Create(pBufferDst, lImageWidth, lImageHeight, 4 * lImageWidth);
unsigned int* palette = new unsigned int[nPaletteEntries];
// Create palette for the bitmap
int color = 0xff0000;
int decrement = color / (nPaletteEntries - 1);
for (int i = 0; i < nPaletteEntries; ++i)
{
BYTE level = (BYTE)(color >> 16);
palette[i] = (0xFF000000 | level << 16 | level << 8 | level);
color -= decrement;
}
unsigned int* pBuffer = (unsigned int*)pBufferDst;
for (int j = lImageHeight - 1; j >= 0; --j)
{
BYTE* pLine = pBitmap->operator [](j);
for (int i = 0; i < lImageWidth; ++i, ++pBuffer, ++pLine)
{
if (*pLine < nPaletteEntries)
{
*pBuffer = palette[*pLine];
}
else
{
*pBuffer = palette[0];
}
}
}
RELEASEARRAYOBJECTS(palette);
pRenderer->DrawImage((IGrObject*)&oImage, 0, 0, dWidth, dHeight);
}
}
}
}
pRenderer->EndCommand(c_nPageType);
}
void CDjVuFileImplementation::CreateGrFrame(IRenderer* pRenderer, GP<DjVuImage>& pPage, bool* pBreak)
{
int nWidth = pPage->get_real_width();
int nHeight = pPage->get_real_height();
BYTE* pBufferDst = NULL;
LONG lImageWidth = 0;
LONG lImageHeight = 0;
// TODO: Реализовать для графического рендерера
//VARIANT var;
//renderer->GetAdditionalParam(L"Pixels", &var);
//pBufferDst = (BYTE*)var.lVal;
//renderer->GetAdditionalParam(L"PixelsWidth", &var);
//lImageWidth = var.lVal;
//renderer->GetAdditionalParam(L"PixelsHeight", &var);
//lImageHeight = var.lVal;
volatile bool* pCancel = pBreak;
if ((NULL != pCancel) && (TRUE == *pCancel))
return;
if (pPage->is_legal_photo() || pPage->is_legal_compound())
{
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
BYTE* pBuffer = pBufferDst;
for (int j = 0; j < lImageHeight; ++j)
{
GPixel* pLine = pImage->operator [](j);
if ((NULL != pCancel) && (TRUE == *pCancel))
return;
for (int i = 0; i < lImageWidth; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
}
else if (pPage->is_legal_bilevel())
{
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GBitmap> pBitmap = pPage->get_bitmap(oRectAll, oRectAll, 4);
int nPaletteEntries = pBitmap->get_grays();
unsigned int* palette = new unsigned int[nPaletteEntries];
// Create palette for the bitmap
int color = 0xff0000;
int decrement = color / (nPaletteEntries - 1);
for (int i = 0; i < nPaletteEntries; ++i)
{
BYTE level = (BYTE)(color >> 16);
palette[i] = (0xFF000000 | level << 16 | level << 8 | level);
color -= decrement;
}
unsigned int* pBuffer = (unsigned int*)pBufferDst;
for (int j = 0; j < lImageHeight; ++j)
{
BYTE* pLine = pBitmap->operator [](j);
if ((NULL != pCancel) && (TRUE == *pCancel))
return;
for (int i = 0; i < lImageWidth; ++i, ++pBuffer, ++pLine)
{
if (*pLine < nPaletteEntries)
{
*pBuffer = palette[*pLine];
}
else
{
*pBuffer = palette[0];
}
}
}
RELEASEARRAYOBJECTS(palette);
}
else
{
// белый фрейм??
//memset(pBufferDst, 0xFF, 4 * lImageWidth * lImageHeight);
GRect oRectAll(0, 0, lImageWidth, lImageHeight);
GP<GPixmap> pImage = pPage->get_pixmap(oRectAll, oRectAll);
if (NULL != pImage)
{
BYTE* pBuffer = pBufferDst;
for (int j = 0; j < lImageHeight; ++j)
{
GPixel* pLine = pImage->operator [](j);
if ((NULL != pCancel) && (TRUE == *pCancel))
return;
for (int i = 0; i < lImageWidth; ++i, pBuffer += 4, ++pLine)
{
pBuffer[0] = pLine->b;
pBuffer[1] = pLine->g;
pBuffer[2] = pLine->r;
pBuffer[3] = 255;
}
}
return;
}
GP<GBitmap> pBitmap = pPage->get_bitmap(oRectAll, oRectAll, 4);
if (NULL != pBitmap)
{
int nPaletteEntries = pBitmap->get_grays();
unsigned int* palette = new unsigned int[nPaletteEntries];
// Create palette for the bitmap
int color = 0xff0000;
int decrement = color / (nPaletteEntries - 1);
for (int i = 0; i < nPaletteEntries; ++i)
{
BYTE level = (BYTE)(color >> 16);
palette[i] = (0xFF000000 | level << 16 | level << 8 | level);
color -= decrement;
}
unsigned int* pBuffer = (unsigned int*)pBufferDst;
for (int j = 0; j < lImageHeight; ++j)
{
BYTE* pLine = pBitmap->operator [](j);
if ((NULL != pCancel) && (TRUE == *pCancel))
return;
for (int i = 0; i < lImageWidth; ++i, ++pBuffer, ++pLine)
{
if (*pLine < nPaletteEntries)
{
*pBuffer = palette[*pLine];
}
else
{
*pBuffer = palette[0];
}
}
}
RELEASEARRAYOBJECTS(palette);
}
}
}
XmlUtils::CXmlNode CDjVuFileImplementation::ParseText(GP<DjVuImage> pPage)
{
XmlUtils::CXmlNode paragraph;
const GP<DjVuText> text(DjVuText::create());
const GP<ByteStream> text_str(pPage->get_text());
if (text_str)
{
text->decode(text_str);
GUTF8String pageText = text->get_xmlText(pPage->get_height());
XmlUtils::CXmlNode hiddenText;
XmlUtils::CXmlNode pageColumn;
XmlUtils::CXmlNode region;
hiddenText.FromXmlStringA(NSDjvu::MakeCString(pageText));
hiddenText.GetNode(L"PAGECOLUMN", pageColumn);
pageColumn.GetNode(L"REGION", region);
region.GetNode(L"PARAGRAPH", paragraph);
}
return paragraph;
}
void CDjVuFileImplementation::TextToRenderer(IRenderer* pRenderer, XmlUtils::CXmlNode oTextNode, double dKoef, bool isView)
{
// Выставим шрифт пустой (чтобы растягивать по всему ректу)
pRenderer->put_FontName(L"DjvuEmptyFont");
//std::wstring csText = oTextNode.GetXml();
XmlUtils::CXmlNodes oLinesNodes;
oTextNode.GetNodes(L"LINE", oLinesNodes);
for (int nLineIndex = 0; nLineIndex < oLinesNodes.GetCount(); ++nLineIndex)
{
XmlUtils::CXmlNode oLineNode;
oLinesNodes.GetAt(nLineIndex, oLineNode);
XmlUtils::CXmlNodes oWordsNodes;
oLineNode.GetNodes(L"WORD", oWordsNodes);
for (int nWordIndex = 0; nWordIndex < oWordsNodes.GetCount(); ++nWordIndex)
{
XmlUtils::CXmlNode oWordNode;
oWordsNodes.GetAt(nWordIndex, oWordNode);
std::wstring csWord = oWordNode.GetText();
std::wstring csCoords = oWordNode.GetAttribute(L"coords");
double arrCoords[4];
ParseCoords(csCoords, arrCoords, dKoef);
DrawPageText(pRenderer, arrCoords, csWord);
}
}
}
void CDjVuFileImplementation::DrawPageText(IRenderer* pRenderer, double* pdCoords, const std::wstring& wsText)
{
pRenderer->put_FontSize(pdCoords[1] - pdCoords[3]);
pRenderer->CommandDrawText(wsText,
(float)(pdCoords[0]),
(float)(pdCoords[3]),
(float)(pdCoords[2] - pdCoords[0]),
(float)(pdCoords[1] - pdCoords[3]));
#ifdef BUILDING_WASM_MODULE
GetGlyphs(pRenderer, wsText, NULL, pdCoords[0], pdCoords[3]);
#endif
}
void CDjVuFileImplementation::ParseCoords(const std::wstring& wsCoordsStr, double* pdCoords, double dKoef)
{
std::vector<std::wstring> vCoords = NSStringExt::Split(wsCoordsStr, L',');
if (vCoords.size() >= 4)
{
for (int nIndex = 0; nIndex < 4; nIndex++)
{
pdCoords[nIndex] = NSDjvu::GetInteger(vCoords.at(nIndex)) * dKoef;
}
}
}