mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-02-10 18:05:41 +08:00
1594 lines
47 KiB
C++
1594 lines
47 KiB
C++
/*
|
||
* (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, ­, &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;
|
||
}
|
||
}
|
||
}
|