diff --git a/.gitattributes b/.gitattributes index 233e8f03ec..79eb7a8979 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8679,6 +8679,9 @@ Test/HtmlTextEditor/Table/images/pencil.png svn_mime_002dtype=application%2Focte Test/Units/DocxOdtTxt/OdtTemplate/Thumbnails/Thumbs.db svn_mime_002dtype=application%2Foctet-stream Test/Units/DocxOdtTxt/OdtTemplate/Thumbnails/thumbnail.png svn_mime_002dtype=application%2Foctet-stream Test/Units/DocxOdtTxt/image1.emf svn_mime_002dtype=application%2Foctet-stream +/XpsFile svnc_tsvn_003alogminsize=5 +XpsFile/XpsFileTest svnc_tsvn_003alogminsize=5 +XpsFile/XpsLib svnc_tsvn_003alogminsize=5 _tags/rev_61879/ASCHTMLRenderer/Resources/common.zip svn_mime_002dtype=application%2Foctet-stream _tags/rev_61879/ASCHTMLRenderer/Resources/imgtrackbar/b_bg_all.gif svn_mime_002dtype=application%2Foctet-stream _tags/rev_61879/ASCHTMLRenderer/Resources/imgtrackbar/b_bg_off.gif svn_mime_002dtype=application%2Foctet-stream diff --git a/XpsFile/XpsFile.cpp b/XpsFile/XpsFile.cpp new file mode 100644 index 0000000000..2feb542103 --- /dev/null +++ b/XpsFile/XpsFile.cpp @@ -0,0 +1,137 @@ +#include "XpsFile.h" +#include "XpsLib/Folder.h" + +#include "../DesktopEditor/common/File.h" +#include "../DesktopEditor/common/Directory.h" +#include "../DesktopEditor/fontengine/FontManager.h" +#include "../DesktopEditor/fontengine/ApplicationFonts.h" +#include "../DesktopEditor/graphics/GraphicsRenderer.h" + +#include "../ASCOfficeUtils/ASCOfficeUtilsLib/OfficeUtils.h" + +using namespace XPS; + +CXpsFile::CXpsFile(CApplicationFonts* pAppFonts) +{ + std::wstring wsTemp = NSFile::CFileBinary::GetTempPath(); + wsTemp += L"/XPS/"; + m_wsTempDirectory = wsTemp; + NSDirectory::CreateDirectory(m_wsTempDirectory); + + m_pAppFonts = pAppFonts; + + // Создаем менеджер шрифтов с собственным кэшем + m_pFontManager = pAppFonts->GenerateFontManager(); + CFontsCache* pMeasurerCache = new CFontsCache(); + pMeasurerCache->SetStreams(pAppFonts->GetStreams()); + m_pFontManager->SetOwnerCache(pMeasurerCache); +} +CXpsFile::~CXpsFile() +{ + Close(); + NSDirectory::DeleteDirectory(m_wsTempDirectory); + RELEASEINTERFACE(m_pFontManager); +} +std::wstring CXpsFile::GetTempDirectory() const +{ + return m_wsTempDirectory; +} +void CXpsFile::SetTempDirectory(const std::wstring& wsDirectory) +{ + NSDirectory::DeleteDirectory(m_wsTempDirectory); + m_wsTempDirectory = wsDirectory; + m_wsTempDirectory += L"/XPS/"; + NSDirectory::CreateDirectory(m_wsTempDirectory); +} +bool CXpsFile::LoadFromFile(const std::wstring& wsSrcFileName, const std::wstring& wsXmlOptions) +{ + Close(); + + // Распаковываем Zip-архив в темповую папку + COfficeUtils oUtils(NULL); + if (S_OK != oUtils.ExtractToDirectory(wsSrcFileName, m_wsTempDirectory, NULL, 0)) + return false; + + m_pFolder = new XPS::Folder(m_pFontManager); + if (!m_pFolder) + return false; + + std::wstring wsPath = m_wsTempDirectory + L"/"; + m_pFolder->ReadFromPath(wsPath); + + return true; +} +void CXpsFile::Close() +{ + if (m_pFolder) + { + m_pFolder->Close(); + delete m_pFolder; + m_pFolder = NULL; + } +} +int CXpsFile::GetPagesCount() +{ + if (!m_pFolder) + return 0; + + return m_pFolder->GetPageCount(); +} +void CXpsFile::GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY) +{ + int nW = 0, nH = 0; + + if (m_pFolder) + m_pFolder->GetPageSize(nPageIndex, nW, nH); + + *pdWidth = nW * 25.4 / 96; + *pdHeight = nH * 25.4 / 96; + *pdDpiX = 96; + *pdDpiY = 96; +} +void CXpsFile::DrawPageOnRenderer(IRenderer* pRenderer, int nPageIndex, bool* pBreak) +{ + if (!m_pFolder) + return; + + m_pFolder->DrawPage(nPageIndex, pRenderer, pBreak); +} +void CXpsFile::ConvertToRaster(int nPageIndex, const std::wstring& wsDstPath, int nImageType) +{ + CFontManager *pFontManager = m_pAppFonts->GenerateFontManager(); + CFontsCache* pFontCache = new CFontsCache(); + pFontCache->SetStreams(m_pAppFonts->GetStreams()); + pFontManager->SetOwnerCache(pFontCache); + + CGraphicsRenderer oRenderer; + oRenderer.SetFontManager(pFontManager); + + double dPageDpiX, dPageDpiY; + double dWidth, dHeight; + GetPageInfo(nPageIndex, &dWidth, &dHeight, &dPageDpiX, &dPageDpiY); + + int nWidth = (int)dWidth * 96 / dPageDpiX; + int nHeight = (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); + + oRenderer.CreateFromBgraFrame(&oFrame); + oRenderer.SetSwapRGB(false); + oRenderer.put_Width(dWidth); + oRenderer.put_Height(dHeight); + + bool bBreak = false; + DrawPageOnRenderer(&oRenderer, nPageIndex, &bBreak); + + oFrame.SaveFile(wsDstPath, nImageType); + RELEASEINTERFACE(pFontManager); +} \ No newline at end of file diff --git a/XpsFile/XpsFile.h b/XpsFile/XpsFile.h new file mode 100644 index 0000000000..7fd0fd2a93 --- /dev/null +++ b/XpsFile/XpsFile.h @@ -0,0 +1,38 @@ +#ifndef _XPS_FILE_H +#define _XPS_FILE_H + +#include + +namespace XPS +{ + class Folder; +} + +class IRenderer; +class CApplicationFonts; +class CFontManager; + +class CXpsFile +{ +public: + CXpsFile(CApplicationFonts* pAppFonts); + ~CXpsFile(); + + bool LoadFromFile(const std::wstring& wsSrcFileName, const std::wstring& wsXmlOptions = L""); + void Close(); + std::wstring GetTempDirectory() const; + void SetTempDirectory(const std::wstring& wsPath); + int GetPagesCount(); + void GetPageInfo(int nPageIndex, double* pdWidth, double* pdHeight, double* pdDpiX, double* pdDpiY); + void DrawPageOnRenderer(IRenderer* pRenderer, int nPageIndex, bool* pBreak); + void ConvertToRaster(int nPageIndex, const std::wstring& wsDstPath, int nImageType); + +private: + + CApplicationFonts* m_pAppFonts; + CFontManager* m_pFontManager; + std::wstring m_wsTempDirectory; + XPS::Folder* m_pFolder; +}; + +#endif // _XPS_FILE_H \ No newline at end of file diff --git a/XpsFile/XpsFile.sln b/XpsFile/XpsFile.sln new file mode 100644 index 0000000000..78eba9ab5b --- /dev/null +++ b/XpsFile/XpsFile.sln @@ -0,0 +1,50 @@ +п»ї +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30723.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XpsFile", "XpsFile.vcxproj", "{DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XpsFileTest", "XpsFileTest\XpsFileTest.vcxproj", "{84BACD6F-275B-4C60-AC5A-F541919728C5}" + ProjectSection(ProjectDependencies) = postProject + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B} = {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Debug|Win32.ActiveCfg = Debug|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Debug|Win32.Build.0 = Debug|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Debug|x64.ActiveCfg = Debug|x64 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Debug|x64.Build.0 = Debug|x64 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Release|Mixed Platforms.Build.0 = Release|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Release|Win32.ActiveCfg = Release|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Release|Win32.Build.0 = Release|Win32 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Release|x64.ActiveCfg = Release|x64 + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B}.Release|x64.Build.0 = Release|x64 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Debug|Win32.ActiveCfg = Debug|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Debug|Win32.Build.0 = Debug|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Debug|x64.ActiveCfg = Debug|x64 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Debug|x64.Build.0 = Debug|x64 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Release|Mixed Platforms.Build.0 = Release|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Release|Win32.ActiveCfg = Release|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Release|Win32.Build.0 = Release|Win32 + {84BACD6F-275B-4C60-AC5A-F541919728C5}.Release|x64.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/XpsFile/XpsFile.vcxproj b/XpsFile/XpsFile.vcxproj new file mode 100644 index 0000000000..5cbf3d9f24 --- /dev/null +++ b/XpsFile/XpsFile.vcxproj @@ -0,0 +1,157 @@ +п»ї + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {DF16B0DF-A4CD-4389-B390-5ED72F4E2A2B} + Win32Proj + XpsFile + + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;_USE_LIBXML2_READER_;LIBXML_READER_ENABLED + true + D:\Subversion\AVS\Sources\TeamlabOffice\trunk\ServerComponents\Common\DocxFormat\Source\XML\libxml2\XML\include;D:\Subversion\AVS\Sources\TeamlabOffice\trunk\ServerComponents\DesktopEditor\freetype-2.5.2\include;D:\Subversion\AVS\Sources\TeamlabOffice\trunk\ServerComponents\DesktopEditor\agg-2.4\include;%(AdditionalIncludeDirectories) + 4267;4244;4800;4018;4005 + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/XpsFile/XpsFileTest/XpsFileTest.cpp b/XpsFile/XpsFileTest/XpsFileTest.cpp new file mode 100644 index 0000000000..8625c09af7 --- /dev/null +++ b/XpsFile/XpsFileTest/XpsFileTest.cpp @@ -0,0 +1,76 @@ +// XpsFileTest.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" + +#include "../XpsFile.h" + +#include +#include +#include "windows.h" + +#include "../../DesktopEditor/common/String.h" +#include "../../DesktopEditor/fontengine/ApplicationFonts.h" + +std::vector GetAllFilesInFolder(std::wstring wsFolder, std::wstring wsExt) +{ + std::vector vwsNames; + + std::wstring wsSearchPath = wsFolder; + wsSearchPath.append(L"*."); + wsSearchPath.append(wsExt); + + WIN32_FIND_DATA oFindData; + HANDLE hFind = ::FindFirstFile(wsSearchPath.c_str(), &oFindData); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + if (!(oFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + vwsNames.push_back(oFindData.cFileName); + } + } while (::FindNextFile(hFind, &oFindData)); + ::FindClose(hFind); + } + return vwsNames; +} +void ConvertFolder(CXpsFile& oReader, std::wstring wsFolderPath) +{ + oReader.Close(); + + std::vector vFiles = GetAllFilesInFolder(wsFolderPath, L"xps"); + for (int nIndex = 0; nIndex < vFiles.size(); nIndex++) + { + std::wstring wsFilePath = wsFolderPath; + wsFilePath.append(vFiles.at(nIndex)); + std::wstring wsFilePathName = (wsFilePath.substr(0, wsFilePath.size() - 4)); + if (oReader.LoadFromFile(wsFilePath.c_str())) + { + int nPagesCount = oReader.GetPagesCount(); + + for (int nPageIndex = 0; nPageIndex < nPagesCount; nPageIndex++) + { + std::wstring wsDstFilePath = wsFilePathName + L"_" + std::to_wstring(nPageIndex) + L".png"; + oReader.ConvertToRaster(nPageIndex, wsDstFilePath.c_str(), 4); + printf("%d of %d %S page %d / %d\n", nIndex, vFiles.size(), vFiles.at(nIndex).c_str(), nPageIndex, nPagesCount); + } + oReader.Close(); + } + else + { + printf("%d of %d %S error\n", nIndex, vFiles.size(), vFiles.at(nIndex).c_str()); + } + } +} + + +void main() +{ + CApplicationFonts oFonts; + oFonts.Initialize(); + + CXpsFile oFile(&oFonts); + oFile.SetTempDirectory(L"D:/Test Files/Temp/"); + ConvertFolder(oFile, L"D:/Test Files//"); +} diff --git a/XpsFile/XpsFileTest/XpsFileTest.vcxproj b/XpsFile/XpsFileTest/XpsFileTest.vcxproj new file mode 100644 index 0000000000..ac904640d8 --- /dev/null +++ b/XpsFile/XpsFileTest/XpsFileTest.vcxproj @@ -0,0 +1,170 @@ +п»ї + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {84BACD6F-275B-4C60-AC5A-F541919728C5} + Win32Proj + XpsFileTest + + + + Application + true + v120 + Unicode + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;_CRT_SECURE_NO_WARNINGS;UNICODE;_UNICODE;_USE_LIBXML2_READER_;LIBXML_READER_ENABLED;%(PreprocessorDefinitions) + true + D:\Subversion\AVS\Sources\TeamlabOffice\trunk\ServerComponents\DesktopEditor\freetype-2.5.2\include;D:\Subversion\AVS\Sources\TeamlabOffice\trunk\ServerComponents\DesktopEditor\agg-2.4\include;D:\Subversion\AVS\Sources\TeamlabOffice\trunk\ServerComponents\Common\DocxFormat\Source\XML\libxml2\XML\include + + + Console + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + NotUsing + + + NotUsing + + + NotUsing + + + Create + Create + Create + Create + + + + + + + \ No newline at end of file diff --git a/XpsFile/XpsFileTest/stdafx.cpp b/XpsFile/XpsFileTest/stdafx.cpp new file mode 100644 index 0000000000..5ec76f69ff --- /dev/null +++ b/XpsFile/XpsFileTest/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// XpsFileTest.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/XpsFile/XpsFileTest/stdafx.h b/XpsFile/XpsFileTest/stdafx.h new file mode 100644 index 0000000000..1a93b2b803 --- /dev/null +++ b/XpsFile/XpsFileTest/stdafx.h @@ -0,0 +1,23 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include + +#ifdef _DEBUG +#pragma comment(lib, "../../Common/DocxFormat/Source/XML/libxml2/win_build/x64/Debug/libxml2.lib") +#pragma comment(lib, "../../ASCOfficeUtils/ASCOfficeUtilsLib/Win/x64/Debug/ASCOfficeUtilsLib.lib") +#pragma comment(lib, "../x64/Debug/XpsFile.lib") +#pragma comment(lib, "../../DesktopEditor/Qt_build/graphics/project/debug/graphics.lib") +#else +#pragma comment(lib, "../x64/Release/XpsFile.lib") +#pragma comment(lib, "../../DesktopEditor/Qt_build/graphics/project/release/graphics.lib") +#endif + + +// TODO: reference additional headers your program requires here diff --git a/XpsFile/XpsFileTest/targetver.h b/XpsFile/XpsFileTest/targetver.h new file mode 100644 index 0000000000..90e767bfce --- /dev/null +++ b/XpsFile/XpsFileTest/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/XpsFile/XpsLib/ContextState.cpp b/XpsFile/XpsLib/ContextState.cpp new file mode 100644 index 0000000000..809b43e608 --- /dev/null +++ b/XpsFile/XpsLib/ContextState.cpp @@ -0,0 +1,58 @@ +#include "ContextState.h" + +#ifndef xpsUnitToMM +#define xpsUnitToMM(x) ((x) * 25.4 / 96) +#endif + +namespace XPS +{ + CContextState::CContextState() : m_oCurrentTransform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) + { + m_lTransformStack.push_back(m_oCurrentTransform); + } + CContextState::~CContextState() + { + } + void CContextState::AddFigure(const std::wstring& wsKey, const std::wstring& wsValue) + { + m_mFigures.insert(std::pair(wsKey, wsValue)); + } + std::wstring CContextState::GetFigure(const std::wstring& wsKey) + { + std::map::iterator oIter = m_mFigures.find(wsKey); + if (oIter != m_mFigures.end()) + return oIter->second; + + return L""; + } + void CContextState::PushTransform(const double arrTransform[6]) + { + Aggplus::CMatrix oTransform(arrTransform[0], arrTransform[1], arrTransform[2], arrTransform[3], arrTransform[4], arrTransform[5]); + m_oCurrentTransform.Multiply(&oTransform); + m_lTransformStack.push_back(m_oCurrentTransform); + } + void CContextState::PopTransform() + { + m_lTransformStack.pop_back(); + m_oCurrentTransform = m_lTransformStack.back(); + } + double CContextState::NormalizeTransform() + { + agg::trans_affine& oMatrix = m_oCurrentTransform.m_agg_mtx; + double dDet = sqrt(oMatrix.sx * oMatrix.sy - oMatrix.shx * oMatrix.shy); + + oMatrix.sx /= dDet; + oMatrix.shx /= dDet; + oMatrix.sy /= dDet; + oMatrix.shy /= dDet; + + return dDet; + } + void CContextState::SetTransformToRenderer(IRenderer* pRenderer) + { + pRenderer->SetTransform(m_oCurrentTransform.m_agg_mtx.sx, m_oCurrentTransform.m_agg_mtx.shy, + m_oCurrentTransform.m_agg_mtx.shx, m_oCurrentTransform.m_agg_mtx.sy, + xpsUnitToMM(m_oCurrentTransform.m_agg_mtx.tx), xpsUnitToMM(m_oCurrentTransform.m_agg_mtx.ty)); + + } +} \ No newline at end of file diff --git a/XpsFile/XpsLib/ContextState.h b/XpsFile/XpsLib/ContextState.h new file mode 100644 index 0000000000..0196dceefb --- /dev/null +++ b/XpsFile/XpsLib/ContextState.h @@ -0,0 +1,34 @@ +#ifndef _XPS_XPSLIB_CONTEXTSTATE_H +#define _XPS_XPSLIB_CONTEXTSTATE_H + +#include "../../DesktopEditor/graphics/Matrix.h" +#include "../../DesktopEditor/graphics/IRenderer.h" + +#include +#include + +namespace XPS +{ + class CContextState + { + public: + + CContextState(); + ~CContextState(); + + void AddFigure(const std::wstring& wsKey, const std::wstring& wsName); + std::wstring GetFigure(const std::wstring& wsKey); + void PushTransform(const double arrTransform[6]); + void PopTransform(); + double NormalizeTransform(); + void SetTransformToRenderer(IRenderer* pRenderer); + + public: + + Aggplus::CMatrix m_oCurrentTransform; + std::list m_lTransformStack; + std::map m_mFigures; + }; +} + +#endif //_XPS_XPSLIB_CONTEXTSTATE_H \ No newline at end of file diff --git a/XpsFile/XpsLib/Folder.cpp b/XpsFile/XpsLib/Folder.cpp new file mode 100644 index 0000000000..c5bc12a05f --- /dev/null +++ b/XpsFile/XpsLib/Folder.cpp @@ -0,0 +1,116 @@ +#include "Folder.h" +#include "../../Common/DocxFormat/Source/XML/xmlutils.h" + +namespace XPS +{ + Folder::Folder(CFontManager* pFontManager) + { + m_pFontManager = pFontManager; + m_mPages.clear(); + } + Folder::~Folder() + { + Close(); + } + bool Folder::ReadFromPath(const std::wstring& wsPath) + { + Close(); + + m_wsPath = wsPath; + + XmlUtils::CXmlNode oNode; + XmlUtils::CXmlNodes arrNodes; + XmlUtils::CXmlNode oSubnode; + + std::wstring wsRelsPath = NormalizePath(wsPath + L"_rels/.rels"); + if (!oNode.FromXmlFile(wsRelsPath.c_str())) + return false; + + // Checking root node + if (L"Relationships" != oNode.GetName()) + return false; + + if (!oNode.GetNodes(L"Relationship", arrNodes)) + return false; + + std::wstring wsFile; + for (int nIndex = 0, nCount = arrNodes.GetCount(); nIndex < nCount; nIndex++) + { + arrNodes.GetAt(nIndex, oNode); + + if (L"http://schemas.microsoft.com/xps/2005/06/fixedrepresentation" == oNode.GetAttribute(L"Type")) + { + wsFile = oNode.GetAttribute(L"Target"); + break; + } + + if (nIndex == nCount - 1) + return false; + } + + if (!oNode.FromXmlFile((wsPath + wsFile).c_str())) + return false;; + + // Checking root node + if (L"FixedDocumentSequence" != oNode.GetName()) + return false; + + if (!oNode.GetNode(L"DocumentReference", oSubnode)) + return false; + + wsFile = oSubnode.GetAttribute(L"Source"); + + if (!oNode.FromXmlFile((m_wsPath + wsFile).c_str())) + return false; + + if (L"FixedDocument" != oNode.GetName()) + return false; + + if (!oNode.GetNodes(L"PageContent", arrNodes)) + return false; + + std::wstring wsFilePath = GetPath(m_wsPath + wsFile); + std::wstring wsPagePath; + std::wstring wsSource; + + for (int nIndex = 0, nCount = arrNodes.GetCount(); nIndex < nCount; nIndex++) + { + arrNodes.GetAt(nIndex, oNode); + wsSource = oNode.GetAttribute(L"Source"); + if('/' == wsSource[0]) + wsPagePath = m_wsPath + wsSource; + else + wsPagePath = wsFilePath + wsSource; + + m_mPages.insert(std::pair(nIndex, new XPS::Page(wsPagePath, wsPath, &m_oFontList, m_pFontManager))); + } + + return true; + } + int Folder::GetPageCount()const + { + return (int)m_mPages.size(); + } + void Folder::GetPageSize(int nPageIndex, int& nW, int& nH) + { + std::map::const_iterator oIter = m_mPages.find(nPageIndex); + if (oIter != m_mPages.end()) + oIter->second->GetSize(nW, nH); + } + void Folder::DrawPage(int nPageIndex, IRenderer* pRenderer, bool* pbBreak) + { + std::map::const_iterator oIter = m_mPages.find(nPageIndex); + if (oIter != m_mPages.end()) + oIter->second->Draw(pRenderer, pbBreak); + } + void Folder::Close() + { + for (std::map::iterator oIter = m_mPages.begin(); oIter != m_mPages.end(); oIter++) + { + if (oIter->second) + delete oIter->second; + } + m_mPages.clear(); + m_oFontList.Clear(); + } +} \ No newline at end of file diff --git a/XpsFile/XpsLib/Folder.h b/XpsFile/XpsLib/Folder.h new file mode 100644 index 0000000000..332ac7d2e6 --- /dev/null +++ b/XpsFile/XpsLib/Folder.h @@ -0,0 +1,39 @@ +#ifndef _XPS_XPSLIB_FOLDER_H +#define _XPS_XPSLIB_FOLDER_H + +#include "FontList.h" +#include "Page.h" +#include + +#define UNICODE +#define _UNICODE +#define _USE_LIBXML2_READER_ +#define LIBXML_READER_ENABLED + +#include "../../DesktopEditor/graphics/IRenderer.h" +#include "../../DesktopEditor/graphics/TemporaryCS.h" + +namespace XPS +{ + class Folder + { + public: + Folder(CFontManager* pFontManager); + ~Folder(); + + bool ReadFromPath(const std::wstring& wsPath); + int GetPageCount() const; + void GetPageSize(int nPageIndex, int& nW, int& nH); + void DrawPage(int nPageIndex, IRenderer* pRenderer, bool* pbBreak); + void Close(); + + private: + + std::wstring m_wsPath; + std::map m_mPages; + CFontList m_oFontList; + CFontManager* m_pFontManager; + }; +} + +#endif //_XPS_XPSLIB_FOLDER_H \ No newline at end of file diff --git a/XpsFile/XpsLib/FontList.h b/XpsFile/XpsLib/FontList.h new file mode 100644 index 0000000000..9d99417691 --- /dev/null +++ b/XpsFile/XpsLib/FontList.h @@ -0,0 +1,103 @@ +#ifndef _XPS_XPSLIB_FONTLIST_H +#define _XPS_XPSLIB_FONTLIST_H + +#include +#include +#include + +#include "../../DesktopEditor/graphics/TemporaryCS.h" +#include "../../DesktopEditor/common/File.h" +#include "Utils.h" + +namespace XPS +{ + class CFontList + { + public: + + CFontList() + { + m_oCS.InitializeCriticalSection(); + } + ~CFontList() + { + m_oCS.DeleteCriticalSection(); + } + void Clear() + { + m_mList.clear(); + } + void Check(const std::wstring& wsName, const std::wstring& wsFontPath) + { + m_oCS.Enter(); + if (!Find(wsName)) + { + Add(wsName); + + unsigned char sKey[16]; + GetFontKey(wsName, sKey); + + NSFile::CFileBinary oFile; + oFile.OpenFile(wsFontPath, true); + + unsigned char sFontData[32]; + DWORD dwBytesRead; + oFile.ReadFile(sFontData, 32, dwBytesRead); + + for (int nIndex = 0; nIndex < 32; nIndex++) + sFontData[nIndex] ^= sKey[nIndex % 16]; + + FILE* pFile = oFile.GetFileNative(); + fseek(pFile, 0, SEEK_SET); + fwrite(sFontData, 1, 32, pFile); + fclose(pFile); + } + m_oCS.Leave(); + } + private: + + bool Find(const std::wstring& wsName) + { + std::map::iterator oIter = m_mList.find(wsName); + if (oIter != m_mList.end()) + return oIter->second; + + return false; + } + void Add(const std::wstring& wsName) + { + m_mList.insert(std::pair(wsName, true)); + } + void GetFontKey(const std::wstring& wsName, unsigned char* sKey) + { + int k = 0; + for (int i = wsName.length() - 1; i >= 0; i--) + { + if ('-' != wsName[i]) + { + sKey[k] = (unsigned char)GetIntegerFromHex(wsName.substr(i - 1, 2)); + i--; + k++; + } + } + } + int GetIntegerFromHex(const std::wstring& wsString) + { + if (0 == wsString.size()) + return 0; + + std::wistringstream wiss(wsString); + + int nValue = 0; + wiss >> std::hex >> nValue; + return nValue; + } + + private: + + NSCriticalSection::CRITICAL_SECTION m_oCS; + std::map m_mList; + }; +} + +#endif // _XPS_XPSLIB_FONTLIST_H \ No newline at end of file diff --git a/XpsFile/XpsLib/Page.cpp b/XpsFile/XpsLib/Page.cpp new file mode 100644 index 0000000000..68fe20efc1 --- /dev/null +++ b/XpsFile/XpsLib/Page.cpp @@ -0,0 +1,739 @@ +#include "Page.h" +#include +#include "../../DesktopEditor/common/String.h" +#include "../../DesktopEditor/graphics/structures.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef xpsUnitToMM +#define xpsUnitToMM(x) ((x) * 25.4 / 96) +#endif + +namespace XPS +{ + static inline void PageCommandL(std::vector& arrElements, double& dCurX, double& dCurY, IRenderer* pRenderer, int& nPos) + { + dCurX = GetDouble(arrElements[nPos + 1]); + dCurY = GetDouble(arrElements[nPos + 2]); + nPos += 2; + pRenderer->PathCommandLineTo(xpsUnitToMM(dCurX), xpsUnitToMM(dCurY)); + } + static inline void PageCommandA(std::vector& arrElements, double& dCurX, double& dCurY, IRenderer* pRenderer, int& nPos) + { + Aggplus::CMatrix tmatx, rmatx, smatx, itmatx, irmatx, ismatx; + double x_cur_temp = dCurX; + double y_cur_temp = dCurY; + double x_end = GetDouble(arrElements[nPos + 6]); + double y_end = GetDouble(arrElements[nPos + 7]); + + tmatx.Translate(-dCurX, -dCurY); + tmatx.TransformPoint(x_cur_temp, y_cur_temp); + tmatx.TransformPoint(x_end, y_end); + + double angle = GetDouble(arrElements[nPos + 3]); + rmatx.Rotate(-angle); + rmatx.TransformPoint(x_cur_temp, y_cur_temp); + rmatx.TransformPoint(x_end, y_end); + + double rx = GetDouble(arrElements[nPos + 1]); + double ry = GetDouble(arrElements[nPos + 2]); + smatx.Scale(ry / rx, 1); + smatx.TransformPoint(x_cur_temp, y_cur_temp); + smatx.TransformPoint(x_end, y_end); + + double mid_x = (x_cur_temp + x_end) / 2.0, mid_y = (y_cur_temp + y_end) / 2.0; + double vect_x = x_end - x_cur_temp, vect_y = y_end - y_cur_temp; + double length = sqrt(vect_x * vect_x + vect_y * vect_y); + double halfChord = length / 2.0; + bool isLarge = GetBool(arrElements[nPos + 4]); + bool isCCW = !GetBool(arrElements[nPos + 5]); + double rotated_x, rotated_y; + + if (isLarge == isCCW) + { + rotated_x = -vect_y; + rotated_y = vect_x; + } + else + { + rotated_x = vect_y; + rotated_y = -vect_x; + } + + rotated_x = rotated_x / length; + rotated_y = rotated_y / length; + + double centerDistance = sqrt(max(ry * ry - halfChord * halfChord, 0)); + double center_x = mid_x + centerDistance * rotated_x, center_y = mid_y + centerDistance * rotated_y; + + double angle1 = atan2(y_cur_temp - center_y, x_cur_temp - center_x); + double angle2 = atan2(y_end - center_y, x_end - center_x); + + if ((!isCCW) && (abs(y_end - center_y) < 0.000001) && (x_end - center_x < 0)) + angle2 = -M_PI; + if ((isCCW) && (abs(y_cur_temp - center_y) < 0.000001) && (x_cur_temp - center_x < 0)) + angle1 = -M_PI; + + if (isLarge == (abs(angle2 - angle1) < M_PI)) + { + if (angle1 < angle2) + angle1 += 2 * M_PI; + else + angle2 += 2 * M_PI; + } + if (abs(angle2 - angle1) == M_PI) + { + if ((angle1 < angle2) && (isCCW) && (angle1 != -M_PI) && (angle1 != 0.0) && (angle1 != M_PI)) + angle1 += 2 * M_PI; + } + + itmatx.Translate(dCurX, dCurY); + irmatx.Rotate(angle); + ismatx.Scale(rx / ry, 1); + + int max = (int)((4 * (rx + ry) * abs(angle2 - angle1) / (2 * M_PI)) / 1/*tolerance*/); + + double x, y; + for (int counter = 0; counter <= max; counter++) + { + double angle_cur = ((max - counter) * angle1 + counter * angle2) / max; + x = center_x + ry * cos(angle_cur); + y = center_y + ry * sin(angle_cur); + + // Transform the point back + ismatx.TransformPoint(x, y); + irmatx.TransformPoint(x, y); + itmatx.TransformPoint(x, y); + pRenderer->PathCommandLineTo(xpsUnitToMM(x), xpsUnitToMM(y)); + } + + dCurX = x; + dCurY = y; + nPos += 7; + } + static inline void PageCommandC(std::vector& arrElements, double& dCurX, double& dCurY, double& dCpX, double& dCpY, IRenderer* pRenderer, int& nPos) + { + dCpX = GetDouble(arrElements[nPos + 3]); + dCpY = GetDouble(arrElements[nPos + 4]); + dCurX = GetDouble(arrElements[nPos + 5]); + dCurY = GetDouble(arrElements[nPos + 6]); + + pRenderer->PathCommandCurveTo(xpsUnitToMM(GetDouble(arrElements[nPos + 1])), xpsUnitToMM(GetDouble(arrElements[nPos + 2])), xpsUnitToMM(dCpX), xpsUnitToMM(dCpY), xpsUnitToMM(dCurX), xpsUnitToMM(dCurY)); + nPos += 6; + } + static inline void PageCommandQ(std::vector& arrElements, double& dCurX, double& dCurY, IRenderer* pRenderer, int& nPos) + { + double x1 = 2.0 * GetDouble(arrElements[nPos + 1]); + double y1 = 2.0 * GetDouble(arrElements[nPos + 2]); + double x2 = GetDouble(arrElements[nPos + 3]); + double y2 = GetDouble(arrElements[nPos + 4]); + + pRenderer->PathCommandCurveTo(xpsUnitToMM((dCurX + x1) / 3.0), xpsUnitToMM((dCurY + y1) / 3.0), xpsUnitToMM((x1 + x2) / 3.0), xpsUnitToMM((y1 + y2) / 3.0), xpsUnitToMM(x2), xpsUnitToMM(y2)); + dCurX = x2; + dCurY = y2; + nPos += 4; + } + static inline void PageCommandS(std::vector& arrElements, double& dCurX, double& dCurY, double& dCpX, double& dCpY, IRenderer* pRenderer, int& nPos) + { + dCpX = 2 * dCurX - dCpX; + dCpY = 2 * dCurY - dCpY; + + dCurX = GetDouble(arrElements[nPos + 3]); + dCurY = GetDouble(arrElements[nPos + 4]); + pRenderer->PathCommandCurveTo(xpsUnitToMM(dCpX), xpsUnitToMM(dCpY), + xpsUnitToMM(GetDouble(arrElements[nPos + 1])), xpsUnitToMM(GetDouble(arrElements[nPos + 2])), + xpsUnitToMM(dCurX), xpsUnitToMM(dCurY)); + + dCpX = GetDouble(arrElements[nPos + 1]); + dCpY = GetDouble(arrElements[nPos + 2]); + nPos += 4; + } + Page::Page(const std::wstring& wsPagePath, const std::wstring& wsRootPath, CFontList* pFontList, CFontManager* pFontManager) + { + m_wsPagePath = wsPagePath; + m_wsRootPath = wsRootPath; + m_pFontList = pFontList; + m_pFontManager = pFontManager; + } + Page::~Page() + { + } + void Page::GetSize(int& nW, int& nH) const + { + XmlUtils::CXmlNode oNode; + + if (!oNode.FromXmlFile(m_wsPagePath.c_str())) + return; + + if (L"FixedPage" != oNode.GetName()) + return; + + nW = XmlUtils::GetInteger(oNode.GetAttribute(L"Width")); + nH = XmlUtils::GetInteger(oNode.GetAttribute(L"Height")); + } + void Page::Draw(IRenderer* pRenderer, bool* pbBreak) + { + XmlUtils::CXmlNode oNode; + + if (!oNode.FromXmlFile(m_wsPagePath.c_str())) + return; + + if (L"FixedPage" != oNode.GetName()) + return; + + CContextState oState; + + XmlUtils::CXmlNode oNodeResources; + if (oNode.GetNode(L"FixedPage.Resources", oNodeResources)) + { + XmlUtils::CXmlNode oNodeDictionary; + if (oNodeResources.GetNode(L"ResourceDictionary", oNodeDictionary)) + { + std::wstring wsXmlSource = oNodeDictionary.GetAttribute(L"Source"); + if (L"" != wsXmlSource) + { + std::wstring wsPath = m_wsRootPath + wsXmlSource; + + XmlUtils::CXmlNode oNodeSource; + oNodeSource.FromXmlFile(wsPath.c_str()); + if (oNodeSource.IsValid()) + { + XmlUtils::CXmlNodes arrNodes; + if (oNodeSource.GetNodes(L"PathGeometry", arrNodes)) + { + for (int nIndex = 0, nCount = arrNodes.GetCount(); nIndex < nCount; nIndex++) + { + XmlUtils::CXmlNode oNode; + arrNodes.GetAt(nIndex, oNode); + std::wstring wsKey = oNode.GetAttribute(L"x:Key"); + std::wstring wsValue = oNode.GetAttribute(L"Figures"); + + wsKey = L"{StaticResource " + wsKey + L"}"; + oState.AddFigure(wsKey, wsValue); + } + } + } + } + else + { + XmlUtils::CXmlNodes arrNodes; + if (oNodeDictionary.GetNodes(L"PathGeometry", arrNodes)) + { + for (int nIndex = 0, nCount = arrNodes.GetCount(); nIndex < nCount; nIndex++) + { + XmlUtils::CXmlNode oNode; + arrNodes.GetAt(nIndex, oNode); + + std::wstring wsKey = oNode.GetAttribute(L"x:Key"); + std::wstring wsValue = oNode.GetAttribute(L"Figures"); + + wsKey = (L"{StaticResource " + wsKey + L"}"); + oState.AddFigure(wsKey, wsValue); + } + } + } + } + } + + DrawCanvas(oNode, pRenderer, &oState, pbBreak); + return; + } + void Page::DrawCanvas(XmlUtils::CXmlNode& oCanvasNode, IRenderer* pRenderer, CContextState* pState, bool* pbBreak) + { + bool bClip = false; + std::wstring wsClip = oCanvasNode.GetAttribute(L"Clip", L""); + if (L"" != wsClip) + { + std::wstring wsValue = pState->GetFigure(wsClip); + if (L"" != wsValue) + wsClip = wsValue; + + bClip = true; + pRenderer->PathCommandStart(); + pRenderer->BeginCommand(c_nClipType); + pRenderer->put_ClipMode(0); + pRenderer->BeginCommand(c_nPathType); + + VmlToRenderer(wsClip, pRenderer); + + pRenderer->EndCommand(c_nPathType); + pRenderer->EndCommand(c_nClipType); + pRenderer->PathCommandEnd(); + } + + bool bTransform = false; + std::wstring wsTransform = oCanvasNode.GetAttribute(L"RenderTransform", L""); + if (L"" != wsTransform) + { + bTransform = true; + TransformToRenderer(wsTransform, pRenderer, pState); + } + + XmlUtils::CXmlNodes arrNodes; + XmlUtils::CXmlNode oNode; + std::wstring wsNodeName; + oCanvasNode.GetNodes(L"*", arrNodes); + for (int nIndex = 0, nCount = arrNodes.GetCount(); nIndex < nCount; nIndex++) + { + arrNodes.GetAt(nIndex, oNode); + wsNodeName = oNode.GetName(); + wsNodeName = RemoveNamespace(wsNodeName); + if (L"Glyphs" == wsNodeName) + DrawGlyph(oNode, pRenderer, pState); + else if (L"Canvas" == wsNodeName) + DrawCanvas(oNode, pRenderer, pState, pbBreak); + else if (L"Canvas.RenderTransform" == wsNodeName) + { + if (!bTransform) + { + CanvasTransform(oNode, pRenderer, pState); + bTransform = true; + } + } + else if (L"Path" == wsNodeName) + DrawPath(oNode, pRenderer, pState); + + if (NULL != pbBreak) + { + if (*pbBreak) + return; + } + } + + if (bClip) + { + pRenderer->BeginCommand(c_nResetClipType); + pRenderer->EndCommand(c_nResetClipType); + } + + if (bTransform) + ResetTransform(pRenderer, pState); + } + bool Page::VmlToRenderer(std::wstring& wsString, IRenderer* pRenderer) + { + bool bResult = false; + double dCurX = 0.0, dCurY = 0.0; + double dCpX = 0.0, dCpY = 0.0; + + bool bPrevCommandIsCurve = false; + + PrepareVmlString(wsString); + std::vector arrElements = NSString::Split(wsString, L" ,"); + + int nElementsCount = (int)arrElements.size(); + for (int nPos = 0; nPos < nElementsCount; nPos++) + { + bPrevCommandIsCurve = false; + if (L"F" == arrElements[nPos]) + { + bResult = GetBool(arrElements[nPos + 1]); + } + else if (L"M" == arrElements[nPos] || L"m" == arrElements[nPos]) + { + dCurX = GetDouble(arrElements[nPos + 1]); + dCurY = GetDouble(arrElements[nPos + 2]); + nPos += 2; + pRenderer->PathCommandMoveTo(xpsUnitToMM(dCurX), xpsUnitToMM(dCurY)); + } + else if (L"L" == arrElements[nPos] || L"l" == arrElements[nPos]) + { + PageCommandL(arrElements, dCurX, dCurY, pRenderer, nPos); + + if (nPos + 2 < nElementsCount) + { + while ((nPos + 2 < nElementsCount) && (!IsAlpha(arrElements[nPos + 1][0]))) + { + PageCommandL(arrElements, dCurX, dCurY, pRenderer, nPos); + } + } + } + else if (L"A" == arrElements[nPos] || L"a" == arrElements[nPos]) + { + PageCommandA(arrElements, dCurX, dCurY, pRenderer, nPos); + + if (nPos + 7 < nElementsCount) + { + while ((nPos + 7 < nElementsCount) && (!IsAlpha(arrElements[nPos + 1][0]))) + { + PageCommandA(arrElements, dCurX, dCurY, pRenderer, nPos); + } + } + } + else if (L"H" == arrElements[nPos] || L"h" == arrElements[nPos]) + { + dCurX = GetDouble(arrElements[nPos + 1]); + pRenderer->PathCommandLineTo(xpsUnitToMM(dCurX), xpsUnitToMM(dCurY)); + nPos += 1; + } + else if (L"V" == arrElements[nPos] || L"v" == arrElements[nPos]) + { + dCurY = GetDouble(arrElements[nPos + 1]); + pRenderer->PathCommandLineTo(xpsUnitToMM(dCurX), xpsUnitToMM(dCurY)); + nPos += 1; + } + else if (L"C" == arrElements[nPos] || L"c" == arrElements[nPos]) + { + PageCommandC(arrElements, dCurX, dCurY, dCpX, dCpY, pRenderer, nPos); + + if (nPos + 6 < nElementsCount) + { + while ((nPos + 6 < nElementsCount) && (!IsAlpha(arrElements[nPos + 1][0]))) + { + PageCommandC(arrElements, dCurX, dCurY, dCpX, dCpY, pRenderer, nPos); + } + } + bPrevCommandIsCurve = true; + } + else if (L"Q" == arrElements[nPos] || L"q" == arrElements[nPos]) + { + PageCommandQ(arrElements, dCurX, dCurY, pRenderer, nPos); + + if (nPos + 4 < nElementsCount) + { + while ((nPos + 4 < nElementsCount) && (!IsAlpha(arrElements[nPos + 1][0]))) + { + PageCommandQ(arrElements, dCurX, dCurY, pRenderer, nPos); + } + } + } + else if (L"S" == arrElements[nPos] || L"s" == arrElements[nPos]) + { + if ((!bPrevCommandIsCurve) || (nPos == 0)) + { + dCpX = dCurX; + dCpY = dCurY; + } + + PageCommandS(arrElements, dCurX, dCurY, dCpX, dCpY, pRenderer, nPos); + + if (nPos + 4 < nElementsCount) + { + while ((nPos + 4 < nElementsCount) && (!IsAlpha(arrElements[nPos + 1][0]))) + { + PageCommandS(arrElements, dCurX, dCurY, dCpX, dCpY, pRenderer, nPos); + } + } + bPrevCommandIsCurve = true; + } + else if (L"Z" == arrElements[nPos] || L"Z" == arrElements[nPos]) + { + pRenderer->PathCommandClose(); + } + } + + return bResult; + } + void Page::PrepareVmlString(std::wstring& wsString) + { + const wchar_t* wsVml = L"FMLHVCQSAZfmlhvcqsaz"; + + std::wstring wsResult; + + int nPos = wsString.find(wsVml); + while (std::wstring::npos != nPos) + { + wsResult += wsString.substr(0, nPos); + wsResult += L" "; + wsResult += wsString.substr(nPos, 1); + wsResult += L" "; + wsString.erase(0, nPos + 1); + nPos = wsString.find(wsVml); + } + wsResult += wsString; + wsString = wsResult; + } + void Page::TransformToRenderer(const std::wstring& wsString, IRenderer* pRenderer, CContextState* pState) + { + std::vector arrElements = NSString::Split(wsString, L','); + + double arrRes[6] ={ 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; + for (int nIndex = 0, nCount = min(6, arrElements.size()); nIndex < nCount; nIndex++) + arrRes[nIndex] = GetDouble(arrElements[nIndex]); + + pState->PushTransform(arrRes); + pState->SetTransformToRenderer(pRenderer); + } + void Page::ResetTransform(IRenderer* pRenderer, CContextState* pState) + { + pState->PopTransform(); + pState->SetTransformToRenderer(pRenderer); + } + void Page::DrawGlyph(XmlUtils::CXmlNode& oRootNode, IRenderer* pRenderer, CContextState* pState) + { + std::wstring wsFontPath = oRootNode.GetAttribute(L"FontUri", L""); + if (L"" != wsFontPath) + { + std::wstring wsFontName = GetFileName(wsFontPath); + wsFontPath = m_wsRootPath + L"/" + wsFontPath; + std::wstring wsExt = GetFileExtension(wsFontPath); + NSString::ToLower(wsExt); + if(L"odttf" == wsExt) + { + NSString::ToLower(wsFontName); + m_pFontList->Check(wsFontName, wsFontPath); + } + wsFontPath = NormalizePath(wsFontPath); + pRenderer->put_FontPath(wsFontPath); + } + + int nBgr, nAlpha; + std::wstring wsFontColor = oRootNode.GetAttribute(L"Fill", L"#FF000000"); + GetBgra(wsFontColor, nBgr, nAlpha); + pRenderer->put_BrushColor1(nBgr & 0x00FFFFFF); + pRenderer->put_BrushAlpha1(nAlpha); + pRenderer->put_BrushType(c_BrushTypeSolid); + + std::wstring wsFontStyle = oRootNode.GetAttribute(L"StyleSimulations", L""); + if (L"ItalicSimulation" == wsFontStyle) + pRenderer->put_FontStyle(0x02); + else if (L"BoldSimulation" == wsFontStyle) + pRenderer->put_FontStyle(0x01); + else if (L"BoldItalicSimulation" == wsFontStyle) + pRenderer->put_FontStyle(0x03); + + std::wstring wsFontSize = oRootNode.GetAttribute(L"FontRenderingEmSize"); + double dFontSize = GetDouble(wsFontSize); + + bool bTransform = false; + std::wstring wsTransform = oRootNode.GetAttribute(L"RenderTransform", L""); + if(L"" != wsTransform) + { + TransformToRenderer(wsTransform, pRenderer, pState); + bTransform = true; + + if(dFontSize < 5) + { + double dDet = pState->NormalizeTransform(); + dFontSize *= dDet; + pState->SetTransformToRenderer(pRenderer); + } + } + pRenderer->put_FontSize(dFontSize * 0.75); + + std::wstring wsText = oRootNode.GetAttribute(L"UnicodeString", L""); + std::wstring wsTextX = oRootNode.GetAttribute(L"OriginX"); + std::wstring wsTextY = oRootNode.GetAttribute(L"OriginY"); + + int nTextLen = wsText.length(); + double dX = GetDouble(wsTextX); + double dY = GetDouble(wsTextY); + + std::wstring wsChar = wsText.substr(0, 1); + + std::wstring wsIndicies = oRootNode.GetAttribute(L"Indices", L""); + std::vector> arrElements = Split(wsIndicies, L';', L','); + + m_pFontManager->LoadFontFromFile(wsFontPath, 0, (float)(dFontSize * 0.75), 96, 96); + for(int nIndex = 0; nIndex < nTextLen - 1; nIndex++) + { + if (nIndex >= arrElements.size()) + arrElements.push_back(std::vector()); + + pRenderer->CommandDrawText(wsChar, xpsUnitToMM(dX), xpsUnitToMM(dY), 0, 0, 0); + + if (arrElements.at(nIndex).size() >= 2) + { + dX += GetDouble(arrElements.at(nIndex).at(1)) * dFontSize / 100.0; + } + else + { + m_pFontManager->LoadString1(wsChar, 0, 0); + TBBox oBox = m_pFontManager->MeasureString2(); + dX += (oBox.fMaxX - oBox.fMinX); + } + + wsChar = wsText.substr(nIndex + 1, 1); + } + + if (nTextLen > 0) + { + pRenderer->CommandDrawText(wsChar, xpsUnitToMM(dX), xpsUnitToMM(dY), 0, 0, 0); + } + + if (bTransform) + ResetTransform(pRenderer, pState); + } + void Page::CanvasTransform(XmlUtils::CXmlNode& oRootNode, IRenderer* pRenderer, CContextState* pState) + { + XmlUtils::CXmlNode oTransformNode; + oRootNode.GetNode(L"MatrixTransform", oTransformNode); + std::wstring wsMatrix = oTransformNode.GetAttribute(L"Matrix"); + TransformToRenderer(wsMatrix, pRenderer, pState); + } + void Page::DrawPath(XmlUtils::CXmlNode& oRootNode, IRenderer* pRenderer, CContextState* pState) + { + bool bTransform = false; + std::wstring wsTransform = oRootNode.GetAttribute(L"RenderTransform", L""); + if (L"" != wsTransform) + { + TransformToRenderer(wsTransform, pRenderer, pState); + bTransform = true; + } + + int nAlpha, nBgr; + std::wstring wsStrokeColor = oRootNode.GetAttribute(L"Stroke", L"#00FFFFFF"); + std::wstring wsPenSize = oRootNode.GetAttribute(L"StrokeThickness", L"1.0"); + GetBgra(wsStrokeColor, nBgr, nAlpha); + pRenderer->put_PenColor(nBgr & 0x00FFFFFF); + pRenderer->put_PenAlpha(nAlpha); + pRenderer->put_PenSize(xpsUnitToMM(GetDouble(wsPenSize))); + + std::wstring wsFill = oRootNode.GetAttribute(L"Fill"); + if (L"" != wsFill) + { + GetBgra(wsFill, nBgr, nAlpha); + pRenderer->put_BrushType(c_BrushTypeSolid); + pRenderer->put_BrushColor1(nBgr & 0x00FFFFFF); + pRenderer->put_BrushAlpha1(nAlpha); + } + else + { + XmlUtils::CXmlNode oFillNode; + if (oRootNode.GetNode(L"Path.Fill", oFillNode)) + FillToRenderer(oFillNode, pRenderer); + else + { + pRenderer->put_BrushAlpha1(0); + pRenderer->put_BrushAlpha2(0); + } + } + + std::wstring wsData = oRootNode.GetAttribute(L"Data"); + if (L"" == wsData) + { + GetDataFromNode(wsData, oRootNode); + } + + if (L'{' == wsData[0]) + { + std::wstring wsValue = pState->GetFigure(wsData); + if (L"" != wsValue) + wsData = wsValue; + else + { + if (bTransform) + ResetTransform(pRenderer, pState); + + return; + } + } + + pRenderer->BeginCommand(c_nPathType); + pRenderer->PathCommandStart(); + + bool bWindingFillMode = false; + if (L'{' != wsData[0]) + bWindingFillMode = VmlToRenderer(wsData, pRenderer); + + int nFillMode = bWindingFillMode ? c_nWindingFillMode | c_nStroke : c_nEvenOddFillMode | c_nStroke; + pRenderer->DrawPath(nFillMode); + + pRenderer->EndCommand(c_nPathType); + pRenderer->PathCommandEnd(); + + if (bTransform) + ResetTransform(pRenderer, pState); + } + void Page::FillToRenderer(XmlUtils::CXmlNode& oRootNode, IRenderer* pRenderer) + { + XmlUtils::CXmlNode oBrushNode; + if (oRootNode.GetNode(L"SolidColorBrush", oBrushNode)) + { + int nBgr, nAlpha; + std::wstring wsColor = oBrushNode.GetAttribute(L"Color", L"#00FFFFFF"); + GetBgra(wsColor, nBgr, nAlpha); + pRenderer->put_BrushType(c_BrushTypeSolid); + pRenderer->put_BrushColor1(nBgr & 0x00FFFFFF); + pRenderer->put_BrushAlpha1(nAlpha); + } + else if (oRootNode.GetNode(L"ImageBrush", oBrushNode)) + { + std::wstring wsImageSource = oBrushNode.GetAttribute(L"ImageSource"); + pRenderer->put_BrushType(c_BrushTypeTexture); + pRenderer->put_BrushTexturePath(m_wsRootPath + wsImageSource); + } + else + { + pRenderer->put_BrushAlpha1(0); + pRenderer->put_BrushAlpha2(0); + } + } + void Page::GetDataFromNode(std::wstring& wsString, XmlUtils::CXmlNode& oNode) + { + wsString = L""; + + XmlUtils::CXmlNode oPathDataNode; + oNode.GetNode(L"Path.Data", oPathDataNode); + + XmlUtils::CXmlNode oGeometryNode; + oPathDataNode.GetNode(_T("PathGeometry"), oGeometryNode); + + std::wstring wsFillMode = oGeometryNode.GetAttribute(L"FillRule", L"EvenOdd"); + if (L"EvenOdd" == wsFillMode) + wsString += L"F 0 "; + else + wsString += L"F 1 "; + + XmlUtils::CXmlNodes arrFigureNodes; + XmlUtils::CXmlNode oFigureNode; + XmlUtils::CXmlNodes arrSegmentNodes; + XmlUtils::CXmlNode oSegmentNode; + oGeometryNode.GetNodes(L"PathFigure", arrFigureNodes); + for (int nFigureIndex = 0, nFiguresCount = arrFigureNodes.GetCount(); nFigureIndex < nFiguresCount; nFigureIndex++) + { + arrFigureNodes.GetAt(nFigureIndex, oFigureNode); + + std::wstring wsStartPoint = oFigureNode.GetAttribute(L"StartPoint"); + wsString += L" M " + wsStartPoint; + + oFigureNode.GetNodes(L"*", arrSegmentNodes); + for (int nSegmentIndex = 0, nSegmentsCount = arrSegmentNodes.GetCount(); nSegmentIndex < nSegmentsCount; nSegmentIndex++) + { + arrSegmentNodes.GetAt(nSegmentIndex, oSegmentNode); + std::wstring wsName = oSegmentNode.GetName(); + if (L"PolyLineSegment" == wsName) + { + wsString += L" L "; + wsString += oSegmentNode.GetAttribute(L"Points"); + } + else if (L"PolyBezierSegment" == wsName) + { + wsString += L" C "; + wsString += oSegmentNode.GetAttribute(L"Points"); + } + else if (L"PolyQuadraticBezierSegment" == wsName) + { + wsString += L" Q "; + wsString += oSegmentNode.GetAttribute(L"Points"); + } + else if (L"ArcSegment" == wsName) + { + wsString += L" A "; + wsString += oSegmentNode.GetAttribute(L"Size"); + wsString += L" "; + wsString += oSegmentNode.GetAttribute(L"RotationAngle"); + wsString += L" "; + + std::wstring wsIsLargeArc = oSegmentNode.GetAttribute(L"IsLargeArc"); + if (GetBool(wsIsLargeArc)) + wsString += L"1 "; + else + wsString += L"0 "; + + std::wstring wsSweepDirection = oSegmentNode.GetAttribute(L"SweepDirection"); + if (L"Counterclockwise" == wsSweepDirection) + wsString += L"0 "; + else + wsString += L"1 "; + wsString += oSegmentNode.GetAttribute(L"Point"); + } + } + + std::wstring wsClosed = oFigureNode.GetAttribute(L"IsClosed"); + if (GetBool(wsClosed)) + wsString += L" Z "; + } + } +} \ No newline at end of file diff --git a/XpsFile/XpsLib/Page.h b/XpsFile/XpsLib/Page.h new file mode 100644 index 0000000000..eafba20053 --- /dev/null +++ b/XpsFile/XpsLib/Page.h @@ -0,0 +1,47 @@ +#ifndef _XPS_XPSLIB_PAGE_H +#define _XPS_XPSLIB_PAGE_H + +#include "../../DesktopEditor/graphics/IRenderer.h" +#include "../../Common/DocxFormat/Source/XML/xmlutils.h" +#include "../../DesktopEditor/fontengine/FontManager.h" + +#include "FontList.h" +#include "Utils.h" +#include "ContextState.h" + +namespace XPS +{ + class Page + { + public: + Page(const std::wstring& wsFile, const std::wstring& Path, CFontList* pFontList, CFontManager* pFontManager); + ~Page(); + + void GetSize(int& nW, int& nH) const; + void Draw(IRenderer* pRenderer, bool* pbBreak); + + private: + + void DrawCanvas(XmlUtils::CXmlNode& oNode, IRenderer* pRenderer, CContextState* pState, bool* pbBreak); + void DrawGlyph(XmlUtils::CXmlNode& oNode, IRenderer* pRenderer, CContextState* pState); + void DrawPath(XmlUtils::CXmlNode& oNode, IRenderer* pRenderer, CContextState* pState); + void CanvasTransform(XmlUtils::CXmlNode& oNode, IRenderer* pRenderer, CContextState* pState); + void FillToRenderer(XmlUtils::CXmlNode& oNode, IRenderer* pRenderer); + + bool VmlToRenderer(std::wstring& wsValue, IRenderer* pRenderer); + void GetDataFromNode(std::wstring& wsString, XmlUtils::CXmlNode& oNode); + void TransformToRenderer(const std::wstring& wsString, IRenderer* pRenderer, CContextState* pState); + void ResetTransform(IRenderer* pRenderer, CContextState* pState); + + void PrepareVmlString(std::wstring& wsString); + + private: + + std::wstring m_wsPagePath; + std::wstring m_wsRootPath; + CFontList* m_pFontList; + CFontManager* m_pFontManager; + }; +} + +#endif // _XPS_XPSLIB_PAGE_H \ No newline at end of file diff --git a/XpsFile/XpsLib/Utils.cpp b/XpsFile/XpsLib/Utils.cpp new file mode 100644 index 0000000000..9d98f6dff9 --- /dev/null +++ b/XpsFile/XpsLib/Utils.cpp @@ -0,0 +1,152 @@ +#include "Utils.h" +#include "../../DesktopEditor/common/String.h" +#include "../../DesktopEditor/common/Types.h" + +namespace XPS +{ + int GetDigit(wchar_t wChar) + { + if (wChar >= '0' && wChar <= '9') + return (int)(wChar - '0'); + if (wChar >= 'a' && wChar <= 'f') + return 10 + (int)(wChar - 'a'); + if (wChar >= 'A' && wChar <= 'F') + return 10 + (int)(wChar - 'A'); + + return 0; + } + bool IsAlpha(wchar_t wChar) + { + return (((wChar >= 'A') && (wChar <= 'Z')) || ((wChar >= 'a') && (wChar <= 'z'))); + } + double GetDouble(const std::wstring& wsString) + { + return _wtof(wsString.c_str()); + } + int GetInteger(const std::wstring& wsString) + { + return _wtoi(wsString.c_str()); + } + bool GetBool(const std::wstring& wsString) + { + std::wstring wsStr = wsString; + NSString::ToLower(wsStr); + if ((wsStr == L"true") || (wsStr == L"t") || (wsStr == L"1") || (wsStr == L"on")) + return true; + + return false; + } + void GetBgra(const std::wstring& wsString, int& nBgr, int& nAlpha) + { + if (L'#' == wsString[0]) + { + std::wstring wsStr = wsString.substr(1); + + while (wsStr.length() < 6) + wsStr = L"0" + wsStr; + + while (wsStr.length() < 8) + wsStr = L"F" + wsStr; + + nAlpha = GetDigit(wsStr[0]); + nAlpha = nAlpha << 4; + nAlpha += GetDigit(wsStr[1]); + + nBgr = GetDigit(wsStr[6]); + nBgr = nBgr << 4; + nBgr += GetDigit(wsStr[7]); + nBgr = nBgr << 4; + nBgr += GetDigit(wsStr[4]); + nBgr = nBgr << 4; + nBgr += GetDigit(wsStr[5]); + nBgr = nBgr << 4; + nBgr += GetDigit(wsStr[2]); + nBgr = nBgr << 4; + nBgr += GetDigit(wsStr[3]); + } + else if (L's' == wsString[0] && L'c' == wsString[1] && L'#' == wsString[2]) + { + std::wstring wsStr = wsString.substr(3); + std::vector arrElements = NSString::Split(wsStr, L','); + + if (3 == arrElements.size()) + { + nAlpha = 255; + nBgr = (((int)(min(GetDouble(arrElements[2]), 1.0) * 255)) << 16) + (((int)(min(GetDouble(arrElements[1]), 1.0) * 255)) << 8) + ((int)(min(GetDouble(arrElements[0]), 1.0) * 255)); + } + else if (4 == arrElements.size()) + { + nAlpha = GetDouble(arrElements[0]) * 255; + nBgr = (((int)(min(GetDouble(arrElements[3]), 1.0) * 255)) << 16) + (((int)(min(GetDouble(arrElements[2]), 1.0) * 255)) << 8) + ((int)(min(GetDouble(arrElements[1]), 1.0) * 255)); + } + } + else + return; + } + std::wstring NormalizePath(const std::wstring& wsPath) + { + std::wstring wsResult = wsPath; + NSString::Replace(wsResult, L"/", L"\\"); + while (std::wstring::npos != wsResult.find(L"\\\\")) + { + NSString::Replace(wsResult, L"\\\\", L"\\"); + } + return wsResult; + } + std::wstring GetPath(const std::wstring& wsPath) + { + std::wstring wsResult; + wsResult = wsPath.substr(0, wsPath.find_last_of('/') + 1); + return wsResult; + } + std::wstring GetFileName(const std::wstring& wsPath) + { + int nCommaPos = wsPath.find_last_of(L'.'); + int nSlashPos = wsPath.find_last_of(L'/'); + + if (std::wstring::npos == nCommaPos) + nCommaPos = wsPath.length(); + if (std::wstring::npos == nSlashPos) + nSlashPos = -1; + + if (nCommaPos < nSlashPos) + return L""; + + std::wstring wsResult = wsPath.substr(nSlashPos + 1, nCommaPos - nSlashPos - 1); + return wsResult; + } + std::wstring GetFileExtension(const std::wstring& wsPath) + { + int nCommaPos = wsPath.find_last_of(L'.'); + + if (std::wstring::npos == nCommaPos) + return L""; + + std::wstring wsResult = wsPath.substr(nCommaPos + 1); + return wsResult; + } + std::wstring RemoveNamespace(const std::wstring& wsString) + { + std::wstring wsResult; + + int nPos = wsString.find(L":"); + if (std::wstring::npos != nPos) + wsResult = wsString.substr(nPos + 1); + else + wsResult = wsString; + + return wsResult; + } + std::vector> Split(const std::wstring& wsString, wchar_t wDelim1, wchar_t wDelim2) + { + std::vector> arrResult; + std::vector arrStrings = NSString::Split(wsString, wDelim1); + int nCount = arrStrings.size(); + for (int nIndex = 0; nIndex < nCount; nIndex++) + { + std::vector arrStr = NSString::Split(arrStrings[nIndex], wDelim2); + arrResult.push_back(arrStr); + } + return arrResult; + } +} \ No newline at end of file diff --git a/XpsFile/XpsLib/Utils.h b/XpsFile/XpsLib/Utils.h new file mode 100644 index 0000000000..3cdaa067cf --- /dev/null +++ b/XpsFile/XpsLib/Utils.h @@ -0,0 +1,24 @@ +#ifndef _XPS_XPSLIB_UTILS_H +#define _XPS_XPSLIB_UTILS_H + +#include +#include + +namespace XPS +{ + bool IsAlpha(wchar_t wChar); + double GetDouble(const std::wstring& wsString); + int GetInteger(const std::wstring& wsString); + bool GetBool(const std::wstring& wsString); + void GetBgra(const std::wstring& wsString, int& nBgr, int& nAlpha); + + std::wstring NormalizePath(const std::wstring& wsPath); + std::wstring GetPath(const std::wstring& wsPath); + std::wstring GetFileName(const std::wstring& wsPath); + std::wstring GetFileExtension(const std::wstring& wsPath); + std::wstring RemoveNamespace(const std::wstring& wsString); + + std::vector> Split(const std::wstring& wsString, wchar_t wDelim1, wchar_t wDelim2); +} + +#endif // _XPS_XPSLIB_UTILS_H \ No newline at end of file