add DjVu GetGlyphs

This commit is contained in:
Kulikova Svetlana
2021-11-11 17:21:46 +03:00
parent 30d3472b62
commit 597155af11
4 changed files with 421 additions and 48 deletions

View File

@ -149,8 +149,8 @@ static DWORD GetLength(BYTE* x)
int main()
{
#define XPS_TEST 1
#define DJVU_TEST 0
#define XPS_TEST 0
#define DJVU_TEST 1
#define PDF_TEST 0
#if PDF_TEST
BYTE* pPdfData = NULL;
@ -386,7 +386,7 @@ int main()
if (nError != 0)
{
Close(test);
RELEASEARRAYOBJECTS(pPdfData);
RELEASEARRAYOBJECTS(pDjVuData);
return 1;
}
int* info = GetInfo(test);
@ -396,6 +396,27 @@ int main()
int height = info[test_page * 3 + 2];
std::cout << "Page " << test_page << " width " << width << " height " << height << std::endl;
std::cout << std::endl;
BYTE* pStructure = GetStructure(test);
DWORD nLength = GetLength(pStructure);
DWORD i = 4;
nLength -= 4;
while (i < nLength)
{
DWORD nPathLength = GetLength(pStructure + i);
i += 4;
std::cout << "Page " << nPathLength;
nPathLength = GetLength(pStructure + i);
i += 4;
std::cout << " Level " << nPathLength;
i += 4; // y 0.0
nPathLength = GetLength(pStructure + i);
i += 4;
std::string oDs = std::string((char*)(pStructure + i), nPathLength);
std::wcout << L" Description "<< UTF8_TO_U(oDs) << std::endl;
i += nPathLength;
}
BYTE* res = NULL;
if (pages_count > 0)
res = GetPixmap(test, test_page, width, height);
@ -411,29 +432,6 @@ int main()
std::cout << std::endl;
BYTE* pGlyphs = GetGlyphs(test, test_page);
DWORD nLength = GetLength(pGlyphs);
DWORD i = 4;
nLength -= 4;
while (i < nLength)
{
DWORD nPathLength = GetLength(pGlyphs + i);
i += 4;
std::string oWord = std::string((char*)(pGlyphs + i), nPathLength);
std::wcout << L"Word " << UTF8_TO_U(oWord);
i += nPathLength;
nPathLength = GetLength(pGlyphs + i);
i += 4;
std::cout << " X " << (double)nPathLength / 100.0;
nPathLength = GetLength(pGlyphs + i);
i += 4;
std::cout << " Y " << (double)nPathLength / 100.0;
nPathLength = GetLength(pGlyphs + i);
i += 4;
std::cout << " W " << (double)nPathLength / 100.0;
nPathLength = GetLength(pGlyphs + i);
i += 4;
std::cout << " H " << (double)nPathLength / 100.0 << std::endl;
}
std::cout << std::endl;
BYTE* pLinks = GetLinks(test, test_page);
@ -463,27 +461,6 @@ int main()
std::cout << " H " << (double)nPathLength / 100.0 << std::endl;
}
std::cout << std::endl;
BYTE* pStructure = GetStructure(test);
nLength = GetLength(pStructure);
i = 4;
nLength -= 4;
while (i < nLength)
{
DWORD nPathLength = GetLength(pStructure + i);
i += 4;
std::cout << "Page " << nPathLength;
nPathLength = GetLength(pStructure + i);
i += 4;
std::cout << " Level " << nPathLength;
i += 4; // y 0.0
nPathLength = GetLength(pStructure + i);
i += 4;
std::string oDs = std::string((char*)(pStructure + i), nPathLength);
std::wcout << L" Description "<< UTF8_TO_U(oDs) << std::endl;
i += nPathLength;
}
Close(test);
RELEASEARRAYOBJECTS(pDjVuData);
RELEASEARRAYOBJECTS(info);

View File

@ -484,6 +484,382 @@ BYTE* CDjVuFileImplementation::GetPageLinks (int nPageIndex)
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;
double dFontSize;
m_pRenderer->get_FontSize(&dFontSize);
if (m_lCurrentFont || (dFontSize != m_dCurrentFontSize))
{
m_lCurrentFont = 0;
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;
// m_pTransform->TransformPoint(_x1, _y1);
// m_pTransform->TransformPoint(_x2, _y2);
LONG nCountChars = m_oLine.GetCountChars();
bool bIsNewLine = 0 == nCountChars;
if (bIsNewLine && (nCountChars != 0))
{
// не совпала baseline. поэтому просто скидываем линию в поток
DumpLine();
}
// теперь нужно определить сдвиг по baseline относительно destination точки
nCountChars = m_oLine.GetCountChars();
double dOffsetX = 0;
if (nCountChars == 0)
{
m_oLine.m_bIsConstX = false;
m_oLine.m_dX = _x1;
m_oLine.m_dY = _y1;
m_oLine.m_ex = _x2 - _x1;
m_oLine.m_ey = _y2 - _y1;
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 = false;
m_oLine.m_dX = _x1;
m_oLine.m_dY = _y1;
m_oLine.m_ex = _x2 - _x1;
m_oLine.m_ey = _y2 - _y1;
}
m_oLine.m_dEndX = _x1;
m_oLine.m_dEndY = _y1;
}
// смотрим, совпадает ли главная часть матрицы.
bool bIsTransform = !(fabs(m_pLastTransform.sx() - 1.0) < 0.001 &&
fabs(m_pLastTransform.sy() - 1.0) < 0.001 &&
fabs(m_pLastTransform.shx()) < 0.001 &&
fabs(m_pLastTransform.shy()) < 0.001);
if (bIsTransform)
bIsDumpFont = true;
LONG nColor1 = 0, nAlpha1 = 255;
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] = 1.0;
_dumpMtx[1] = 0.0;
_dumpMtx[2] = 0.0;
_dumpMtx[3] = 1.0;
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)
{
m_oMeta.WriteBYTE(41); // CMetafile::ctFontName
m_oMeta.AddInt(0); // nCurrentFont
m_oMeta.AddInt(0); // get_FontStyle
m_oMeta.WriteDouble(_dumpSize);
}
if (bIsTransform)
{
m_pLastTransform.SetElements(1.0, 0.0, 0.0, 1.0);
m_oLine.m_bIsSetUpTransform = true;
m_oLine.m_sx = 1.0;
m_oLine.m_shx = 0.0;
m_oLine.m_shy = 0.0;
m_oLine.m_sy = 1.0;
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(L"DjvuEmptyFont", 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;
double dDescender = abs(m_pFontManager->GetDescender()) * dKoef;
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;
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)
{
@ -684,6 +1060,9 @@ void CDjVuFileImplementation::CreateFrame(IRenderer* pRenderer, GP
{
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);
@ -1152,6 +1531,9 @@ void CDjVuFileImplementation::DrawPageText(IRenderer* pRenderer, d
(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)
{

View File

@ -54,6 +54,9 @@
#include "../DesktopEditor/xml/include/xmlutils.h"
#include "../DesktopEditor/graphics/IRenderer.h"
#include "../DesktopEditor/graphics/pro/Fonts.h"
#ifdef BUILDING_WASM_MODULE
#include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h"
#endif
class CDjVuFileImplementation
{
@ -83,6 +86,18 @@ public:
BYTE* GetStructure();
BYTE* GetPageGlyphs(int nPageIndex);
BYTE* GetPageLinks (int nPageIndex);
void GetGlyphs(IRenderer* pRenderer, const std::wstring& bsUnicodeText, unsigned int* pGids, double x, double y);
void DumpLine();
NSWasm::CData m_pPageMeta;
private:
double m_dCurrentFontSize = 0.0;
NSWasm::CHLine m_oLine;
NSWasm::CData m_oMeta;
Aggplus::CMatrix m_pLastTransform;
LONG m_lCurrentFont = -1;
LONG m_nLastBrushColor1 = -1;
LONG m_nLastBrushAlpha1 = -1;
#endif
private:

View File

@ -232,7 +232,6 @@ namespace XPS
pTempUnicodes[nTempUnicodesLen++] = (unsigned int)pWchars[i];
// m_pInternal->m_oWriter.WriteText(m_pTempUnicodes, (const int*)pGids, m_nTempUnicodesLen, x, y, w, h, m_pInternal->m_bIsChangedFontParamBetweenDrawText);
// TODO: CheckTectClipRect();
bool bIsDumpFont = false;
std::wstring sCurrentFontName; double dFontSize;