diff --git a/DesktopEditor/graphics/pro/js/wasm/src/serialize.h b/DesktopEditor/graphics/pro/js/wasm/src/serialize.h index 1446996d23..80dbfcc828 100644 --- a/DesktopEditor/graphics/pro/js/wasm/src/serialize.h +++ b/DesktopEditor/graphics/pro/js/wasm/src/serialize.h @@ -16,6 +16,7 @@ namespace NSWasm unsigned char* m_pDataCur; size_t m_lSizeCur; + LONG m_lSizeofBYTE; public: CData() { @@ -24,6 +25,8 @@ namespace NSWasm m_pDataCur = m_pData; m_lSizeCur = m_lSize; + + m_lSizeofBYTE = sizeof(BYTE); } virtual ~CData() { @@ -81,6 +84,17 @@ namespace NSWasm // такой точности хватит AddInt(value * 100); } + void WriteBYTE(BYTE value) + { + AddSize(m_lSizeofBYTE); + memcpy(m_pDataCur, &value, m_lSizeofBYTE); + m_pDataCur += m_lSizeofBYTE; + m_lSizeCur += m_lSizeofBYTE; + } + void WriteDouble(BYTE value) + { + AddInt(value * 10000); + } void WriteString(unsigned char* value, unsigned int len) { AddSize(len + 4); diff --git a/PdfReader/PdfReader.cpp b/PdfReader/PdfReader.cpp index 0ee7cef906..bf80beb9d6 100644 --- a/PdfReader/PdfReader.cpp +++ b/PdfReader/PdfReader.cpp @@ -731,5 +731,219 @@ return 0; oRes.ClearWithoutAttack(); return res; } + + BYTE* CPdfReader::GetGlyphs2(int nPageIndex) + { + if (!m_pInternal->m_pPDFDocument) + return NULL; + nPageIndex++; + TextOutputControl *pControl = new TextOutputControl(); + pControl->mode = textOutPhysLayout; + NSWasm::CData oRes; + oRes.SkipLen(); + TextOutputDev* pTextDev = new TextOutputDev(NULL, pControl, gFalse); + if (!pTextDev->isOk()) + { + RELEASEOBJECT(pTextDev); + RELEASEOBJECT(pControl); + return NULL; + } + m_pInternal->m_pPDFDocument->displayPage(pTextDev, nPageIndex, 72.0, 72.0, 0, gFalse, gTrue, gTrue); + + TextWordList* pWordList = pTextDev->makeWordList(); + if (!pWordList) + { + RELEASEOBJECT(pTextDev); + RELEASEOBJECT(pControl); + return NULL; + } + CHLine m_oLine; + BYTE nLastColorR = 0, nLastColorG = 0, nLastColorB = 0; + for (int i = 0; i < pWordList->getLength(); i++) + { + TextWord* pWord = pWordList->get(i); + if (!pWord) + continue; + int amount = pWord->getLength(); + for (int j = 0; j < amount; j++) + { + double _x1, _y1, _x2, _y2, r, g, b; + pWord->getCharBBox(j, &_x1, &_y1, &_x2, &_y2); + pWord->getColor(&r, &g, &b); + int nColorR = r, nColorG = g, nColorB = b; + TextFontInfo* pFontInfo = pWord->getFontInfo(); + + 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 && (0 != nCountChars)) + { + // не совпала baseline. поэтому просто скидываем линию в поток + DumpLine(m_oLine); + } + + // теперь нужно определить сдвиг по baseline относительно destination точки + nCountChars = m_oLine.GetCountChars(); + double dOffsetX = 0; + if (0 == nCountChars) + { + 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; + + // теперь посмотрим, может быть нужно вставить пробел?? + CHChar* pLastChar = m_oLine.GetTail(); + if (dOffsetX > (pLastChar->width + 0.5)) + { + // вставляем пробел. Пробел у нас будет не совсем пробел. А специфический + CHChar* pSpaceChar = m_oLine.AddTail(); + pSpaceChar->x = pLastChar->width; + pSpaceChar->width = dOffsetX - pLastChar->width; + pSpaceChar->unicode = 0xFFFF; + pSpaceChar->gid = 0xFFFF; + dOffsetX -= pLastChar->width; + + oRes.WriteBYTE(0); + } + } + else + { + // буква сдвинута влево относительно предыдущей буквы + // на такую ситуацию реагируем просто - просто начинаем новую линию, + // предварительно сбросив старую + DumpLine(m_oLine); + + 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 bIsDumpFont = true; + bool bIsColor = nLastColorR != nColorR || nLastColorG != nColorG || nLastColorB != nColorB; + + BYTE nLenMetaCommands = 0; + if (bIsColor) + nLenMetaCommands += 5; + if (bIsDumpFont) + nLenMetaCommands += 13; + + oRes.WriteBYTE(nLenMetaCommands); + if (bIsDumpFont) + { + int lStyle = 0; + if (pFontInfo->isBold()) + lStyle |= 0x01; + if (pFontInfo->isItalic()) + lStyle |= 0x02; + + oRes.WriteBYTE(41); // CMetafile::ctFontName + oRes.AddInt(0); + oRes.AddInt(lStyle); + oRes.WriteDouble(pWord->getFontSize()); + } + if (bIsColor) + { + nLastColorR = nColorR; + nLastColorG = nColorG; + nLastColorB = nColorB; + + oRes.WriteBYTE(22); // CMetafile::ctBrushColor1 + oRes.WriteBYTE(nLastColorR); + oRes.WriteBYTE(nLastColorG); + oRes.WriteBYTE(nLastColorB); + oRes.WriteBYTE(255); // alpha + } + + double dKoef = 0; // m_oFontManager.m_pFont->Size * 25.4 / (72 * m_oFontManager.m_oCurrentInfo.m_lUnitsPerEm); + double dKoefMetr = dAbsVec; + double dAscender = 0 * dKoef * dKoefMetr; // m_oFontManager.m_oCurrentInfo.m_lAscent * dKoef * dKoefMetr; + double dDescender = 0 * dKoef * dKoefMetr; // m_oFontManager.m_oCurrentInfo.m_lDescent * dKoef * dKoefMetr; + + if (m_oLine.m_dAscent < dAscender) + m_oLine.m_dAscent = dAscender; + if (m_oLine.m_dDescent < dDescender) + m_oLine.m_dDescent = dDescender; + + double dW = 1; // m_oFontManager.MeasureString((const unsigned int*)(input + lIndex), 1, 0, 0, dBoxX, dBoxY, dBoxW, dBoxH); + + CHChar* pChar = m_oLine.AddTail(); + pChar->unicode = pWord->getChar(j); + pChar->gid = j + 1; + pChar->x = dOffsetX; + pChar->width = dW * dAbsVec; + + m_oLine.m_dEndX += dOffsetX * m_oLine.m_ex; + m_oLine.m_dEndY += dOffsetX * m_oLine.m_ey; + } + } + RELEASEOBJECT(pWordList); + oRes.WriteLen(); + + RELEASEOBJECT(pTextDev); + RELEASEOBJECT(pControl); + BYTE* res = oRes.GetBuffer(); + oRes.ClearWithoutAttack(); + return res; + } + void CPdfReader::DumpLine(const CPdfReader::CHLine& m_oLine) + { + + } #endif } diff --git a/PdfReader/PdfReader.h b/PdfReader/PdfReader.h index 005a07b0bd..7a3c62548c 100644 --- a/PdfReader/PdfReader.h +++ b/PdfReader/PdfReader.h @@ -101,6 +101,116 @@ namespace PdfReader virtual BYTE* GetStructure(); virtual BYTE* GetGlyphs(int nPageIndex); virtual BYTE* GetLinks (int nPageIndex); + + struct CHChar + { + int unicode; // юникодное значение + int gid; // индекс глифа в файле + double x; // сдвиг по baseline + double width; // ширина символа (сдвиг до след буквы) + double* matrix; // матрица преобразования (!!! без сдвига) + + CHChar() + { + unicode = 0; + gid = 0; + width = 0; + matrix = NULL; + } + ~CHChar() + { + RELEASEARRAYOBJECTS(matrix); + } + + inline void Clear() + { + unicode = 0; + gid = 0; + width = 0; + + RELEASEARRAYOBJECTS(matrix); + } + }; + struct CHLine + { + double m_dAscent; + double m_dDescent; + double m_dX; + double m_dY; + + double m_dEndX; + double m_dEndY; + + double m_dK; + double m_dB; + double m_ex; + double m_ey; + bool m_bIsConstX; + + CHChar* m_pChars; + LONG m_lSizeChars; + LONG m_lCharsTail; + + CHLine() + { + m_dAscent = 0; + m_dDescent = 0; + m_dX = 0; + m_dY = 0; + + m_dK = 0; + m_dB = 0; + m_bIsConstX = false; + + m_ex = 0; + m_ey = 0; + + m_lSizeChars = 1000; + m_lCharsTail = 0; + m_pChars = new CHChar[m_lSizeChars]; + } + ~CHLine() + { + RELEASEARRAYOBJECTS(m_pChars); + } + + inline CHChar* AddTail() + { + if (m_lCharsTail >= m_lSizeChars) + { + CHChar* pNews = new CHChar[2 * m_lSizeChars]; + for (LONG i = 0; i < m_lSizeChars; ++i) + { + pNews[i] = m_pChars[i]; + } + + RELEASEARRAYOBJECTS(m_pChars); + m_pChars = pNews; + m_lSizeChars *= 2; + } + + CHChar* pChar = &m_pChars[m_lCharsTail]; + ++m_lCharsTail; + pChar->Clear(); + + return pChar; + } + + inline CHChar* GetTail() + { + if (0 == m_lCharsTail) + return NULL; + + return &m_pChars[m_lCharsTail - 1]; + } + + inline LONG GetCountChars() + { + return m_lCharsTail; + } + }; + BYTE* GetGlyphs2(int nPageIndex); + void DumpLine(const CPdfReader::CHLine& m_oLine); #endif private: