Files
DocumentServer-v-9.2.0/core/OOXML/Binary/Presentation/imagemanager.cpp
Yajbir Singh f1b860b25c
Some checks failed
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

690 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

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

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* 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-6 Ernesta Birznieka-Upish
* 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 "imagemanager.h"
#ifndef DISABLE_FILE_DOWNLOADER
#include "../../../Common/Network/FileTransporter/include/FileTransporter.h"
#endif
#include <list>
#include "../../../DesktopEditor/graphics/pro/Image.h"
#include "../../../DesktopEditor/raster/ImageFileFormatChecker.h"
#include "../../../OfficeUtils/src/OfficeUtils.h"
#include "../../../DesktopEditor/common/Directory.h"
#include "../../SystemUtility/File.h"
#include "../../SystemUtility/SystemUtility.h"
#include "../../Base/Unit.h"
namespace NSShapeImageGen
{
const long c_nMaxImageSize = 2000;
CMediaManager::CMediaManager()
{
m_lMaxSizeImage = c_nMaxImageSize;
m_lNextIDImage = 0;
m_lDstFormat = 0;
m_pFontManager = NULL;
}
CMediaManager::~CMediaManager()
{
m_pFontManager = NULL;
}
CMediaInfo CMediaManager::WriteImage(CBgraFrame& oImage, double& x, double& y, double& width, double& height)
{
CMediaInfo info;
if (height < 0)
{
FlipY(oImage);
height = -height;
y -= height;
}
return GenerateImageID(oImage, (std::max)(1.0, width), (std::max)(1.0, height));
}
CMediaInfo CMediaManager::WriteImage(const std::string& strFile, double& x, double& y, double& width, double& height, const std::wstring& strAdditionalFile, int typeAdditionalFile)
{
if (width < 0 && height < 0)
return GenerateImageID(strFile, L"", -1, -1, strAdditionalFile, typeAdditionalFile);
return GenerateImageID(strFile, L"", (std::max)(1.0, width), (std::max)(1.0, height), strAdditionalFile, typeAdditionalFile);
}
CMediaInfo CMediaManager::WriteImage(const std::wstring& strFile, double& x, double& y, double& width, double& height, const std::wstring& strAdditionalFile, int typeAdditionalFile)
{
bool bIsDownload = false;
int n1 = (int)strFile.find(L"www");
int n2 = (int)strFile.find(L"http");
int n3 = (int)strFile.find(L"ftp");
int n4 = (int)strFile.find(L"https");
//если nI сранивать не с 0, то будут проблемы
//потому что в инсталяции мы кладем файлы в /var/www...
if (0 == n1 || 0 == n2 || 0 == n3 || 0 == n4)
bIsDownload = true;
if (bIsDownload)
{
std::wstring strFileUrl = strFile;
XmlUtils::replace_all(strFileUrl, L"\\", L"/");
XmlUtils::replace_all(strFileUrl, L"http:/", L"http://");
XmlUtils::replace_all(strFileUrl, L"https:/", L"https://");
XmlUtils::replace_all(strFileUrl, L"ftp:/", L"ftp://");
CMediaInfo oInfo;
std::map<std::wstring, CMediaInfo>::iterator pPair = m_mapMediaFiles.find(strFileUrl);
if (pPair != m_mapMediaFiles.end())
return pPair->second;
std::wstring strDownload;
#ifndef DISABLE_FILE_DOWNLOADER
NSNetwork::NSFileTransport::CFileDownloader oDownloader(strFileUrl, true);
if (oDownloader.DownloadSync())
{
strDownload = oDownloader.GetFilePath();
CImageFileFormatChecker checker;
if (false == checker.isImageFile(strDownload))
{
strDownload.clear();
}
}
#endif
return GenerateImageID(strDownload, strFileUrl, (std::max)(1.0, width), (std::max)(1.0, height), strAdditionalFile, typeAdditionalFile);
}
if (strAdditionalFile.empty())
{
CMediaInfo info;
NSFile::CFileBinary oFile;
if (false == oFile.OpenFile(strFile) && std::wstring::npos == strFile.find(L"data:base64,"))
{
return info;
}
oFile.CloseFile();
}
if (width < 0 && height < 0)
return GenerateImageID(strFile, L"", -1, -1, strAdditionalFile, typeAdditionalFile);
return GenerateImageID(strFile, L"", (std::max)(1.0, width), (std::max)(1.0, height), strAdditionalFile, typeAdditionalFile);
}
CMediaInfo CMediaManager::WriteMedia(const std::wstring& strFile)
{
bool bIsDownload = false;
int n1 = (int)strFile.find (L"www");
int n2 = (int)strFile.find (L"http");
int n3 = (int)strFile.find (L"ftp");
int n4 = (int)strFile.find (L"https");
//если nI сранивать не с 0, то будут проблемы
//потому что в инсталяции мы кладем файлы в /var/www...
if (0 == n1 || 0 == n2 || 0 == n3 || 0 == n4)
bIsDownload = true;
if (bIsDownload)
{
std::wstring strFileUrl = strFile;
XmlUtils::replace_all(strFileUrl, L"\\", L"/");
XmlUtils::replace_all(strFileUrl, L"http:/", L"http://");
XmlUtils::replace_all(strFileUrl, L"https:/", L"https://");
XmlUtils::replace_all(strFileUrl, L"ftp:/", L"ftp://");
CMediaInfo oInfo;
std::map<std::wstring, CMediaInfo>::iterator pPair = m_mapMediaFiles.find(strFileUrl);
if (pPair != m_mapMediaFiles.end())
return pPair->second;
std::wstring strDownload;
#ifndef DISABLE_FILE_DOWNLOADER
NSNetwork::NSFileTransport::CFileDownloader oDownloader(strFileUrl, true);
if (oDownloader.DownloadSync())
{
strDownload = oDownloader.GetFilePath();
CImageFileFormatChecker checker;
if (false == checker.isImageFile(strDownload))
{
strDownload.clear();
}
}
#endif
return GenerateMediaID(strDownload, strFileUrl);
}
return GenerateMediaID(strFile, L"");
}
void CMediaManager::SetFontManager(NSFonts::IFontManager* pFontManager)
{
m_pFontManager = pFontManager;
}
void CMediaManager::SaveImage(const std::wstring& strFileName, CMediaInfo& oInfo, LONG __width, LONG __height)
{
bool result = false;
CImageFileFormatChecker checker;
std::wstring sTempUnpacked;
std::wstring strFileSrc = strFileName;
COfficeUtils officeUtils(NULL);
bool bIsImage = checker.isImageFile(strFileSrc);
if (false == bIsImage && true == officeUtils.IsArchive(strFileSrc))
{
sTempUnpacked = m_strTempMedia + FILE_SEPARATOR_STR + L"zip_unpacked";
NSDirectory::CreateDirectory(sTempUnpacked);
if (S_OK == officeUtils.ExtractToDirectory(strFileSrc, sTempUnpacked, NULL, 0))
{
std::vector<std::wstring> arrFiles = NSDirectory::GetFiles(sTempUnpacked, false);
if (1 == arrFiles.size())
{
strFileSrc = arrFiles[0];
}
}
else
{//gzip
BYTE *pData = NULL;
DWORD nBytesCount = 0;
NSFile::CFileBinary file;
if (file.ReadAllBytes(strFileSrc, &pData, nBytesCount))
{
ULONG nBytesUncompress = nBytesCount * 10;
BYTE* pDataUncompress = new BYTE[nBytesUncompress];
if (S_OK == officeUtils.Uncompress(pDataUncompress, &nBytesUncompress, pData, nBytesCount))
{
std::wstring tempFile = NSFile::CFileBinary::CreateTempFileWithUniqueName(sTempUnpacked, L"img");
file.CreateFileW(tempFile);
file.WriteFile(pDataUncompress, nBytesUncompress);
file.CloseFile();
strFileSrc = tempFile;
}
if (pDataUncompress) delete []pDataUncompress; pDataUncompress = NULL;
if (pData) delete []pData; pData = NULL;
}
}
bIsImage = checker.isImageFile(strFileSrc);
}
if (bIsImage)
{
if (checker.eFileType == _CXIMAGE_FORMAT_JPG)
{
oInfo.m_eType = itJPG;
OOX::CPath pathSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
CDirectory::CopyFile(strFileSrc, pathSaveItem.GetPath());
result = true;
}
else if (checker.eFileType == _CXIMAGE_FORMAT_GIF)
{
oInfo.m_eType = itGIF;
OOX::CPath pathSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
CDirectory::CopyFile(strFileSrc, pathSaveItem.GetPath());
result = true;
}
else if (checker.eFileType == _CXIMAGE_FORMAT_PNG)
{
oInfo.m_eType = itPNG;
OOX::CPath pathSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
CDirectory::CopyFile(strFileSrc, pathSaveItem.GetPath());
result = true;
}
else if (checker.eFileType == _CXIMAGE_FORMAT_WMF)
{
oInfo.m_eType = itWMF;
OOX::CPath pathSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
CDirectory::CopyFile(strFileSrc, pathSaveItem.GetPath());
result = true;
}
else if (checker.eFileType == _CXIMAGE_FORMAT_EMF)
{
oInfo.m_eType = itEMF;
OOX::CPath pathSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
CDirectory::CopyFile(strFileSrc, pathSaveItem.GetPath());
result = true;
}
else if (checker.eFileType == _CXIMAGE_FORMAT_SVG)
{
oInfo.m_eType = itSVG;
OOX::CPath pathSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
CDirectory::CopyFile(strFileSrc, pathSaveItem.GetPath());
result = true;
}
else
{
CBgraFrame oBgraFrame;
if (oBgraFrame.OpenFile(strFileSrc) == true)
{
SaveImage(oBgraFrame, oInfo, __width, __height);
result = true;
}
}
}
if (false == result)
{
//конвертация неудачная - берем оригинальный файл
OOX::CPath pathOriginal = strFileSrc;
//default is itJPG. set itUnknown to use original extension
oInfo.m_eType = itUnknown;
oInfo.m_sExt = pathOriginal.GetExtention();
std::wstring strSaveItem = oInfo.GetPathWithoutExtension();
strSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + strSaveItem + pathOriginal.GetExtention();
CDirectory::CopyFile(strFileSrc, strSaveItem);
}
if (false == sTempUnpacked.empty())
{
NSDirectory::DeleteDirectory(sTempUnpacked);
}
}
void CMediaManager::SaveImage(CBgraFrame& oBgraFrame, CMediaInfo& oInfo, LONG __width, LONG __height)
{
LONG lWidth = oBgraFrame.get_Width();
LONG lHeight = oBgraFrame.get_Height();
oInfo.m_eType = GetImageType(oBgraFrame);
std::wstring strSaveItem = L"";
unsigned int nOutputFormat;
if (itJPG == oInfo.m_eType)
{
strSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
nOutputFormat = _CXIMAGE_FORMAT_JPG;
}
else
{
oInfo.m_eType = itPNG;
strSaveItem = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
nOutputFormat = _CXIMAGE_FORMAT_PNG;
}
OOX::CPath pathSaveItem = strSaveItem;
LONG lMaxSize = (std::min)((std::max)(lWidth, lHeight), m_lMaxSizeImage);
if (!((lWidth <= lMaxSize) && (lHeight <= lMaxSize)))
{
LONG lW = 0;
LONG lH = 0;
double dAspect = (double)lWidth / lHeight;
if (lWidth >= lHeight)
{
lW = lMaxSize;
lH = (LONG)((double)lW / dAspect);
}
else
{
lH = lMaxSize;
lW = (LONG)(dAspect * lH);
}
oBgraFrame.Resize(lW, lH);
}
oBgraFrame.SaveFile(std::wstring(pathSaveItem.GetPath()), nOutputFormat);
}
CMediaInfo CMediaManager::GenerateImageID(CBgraFrame& punkData, double dWidth, double dHeight)
{
CMediaInfo oInfo;
LONG lWidth = (LONG)(dWidth * 96 / 25.4);
LONG lHeight = (LONG)(dHeight * 96 / 25.4);
BYTE* pBuffer = punkData.get_Data();
LONG lLen = 4 * punkData.get_Width() * punkData.get_Height();
DWORD dwSum = m_oCRC.Calc(pBuffer, lLen);
std::map<DWORD, CMediaInfo>::iterator pPair = m_mapMediaData.find(dwSum);
if (m_mapMediaData.end() == pPair)
{
// нужно добавить
++m_lNextIDImage;
oInfo.m_lID = m_lNextIDImage;
SaveImage(punkData, oInfo, lWidth, lHeight);
m_mapMediaData.insert(std::make_pair(dwSum, oInfo));
}
else
{
oInfo = pPair->second;
}
return oInfo;
}
CMediaInfo CMediaManager::GenerateImageID(std::string strFileName, const std::wstring & strUrl, double dWidth, double dHeight, const std::wstring& strAdditionalFile, int typeAdditionalFile)
{
if (0 == strFileName.find("data:base64,"))
{
int nHeaderSize = 12;
int nBase64DataSize = (int)strFileName.length() - nHeaderSize;
int dstLen = NSBase64::Base64DecodeGetRequiredLength(nBase64DataSize);
BYTE* pDstBuffer = new BYTE[dstLen];
NSBase64::Base64Decode(strFileName.c_str() + nHeaderSize, nBase64DataSize, pDstBuffer, &dstLen);
CImageFileFormatChecker checker;
std::wstring sImageExtension = checker.DetectFormatByData(pDstBuffer, dstLen);
std::wstring tempFilePath = m_strTempMedia + FILE_SEPARATOR_STR;
std::wstring strFileNameNew = NSFile::CFileBinary::CreateTempFileWithUniqueName(tempFilePath, L"img") + L"." + sImageExtension;
NSFile::CFileBinary oTempFile;
oTempFile.CreateFile(strFileNameNew);
oTempFile.WriteFile((void*)pDstBuffer, (DWORD)dstLen);
oTempFile.CloseFile();
RELEASEARRAYOBJECTS(pDstBuffer);
return GenerateImageID(strFileNameNew, strUrl, dWidth, dHeight, strAdditionalFile, typeAdditionalFile);
}
return CMediaInfo();
}
CMediaInfo CMediaManager::GenerateImageID(std::wstring strFileName, const std::wstring & strUrl, double dWidth, double dHeight, const std::wstring& strAdditionalFile, int typeAdditionalFile)
{
if (0 == strFileName.find(L"data:base64,"))
{
int nHeaderSize = 12;
int nBase64DataSize = (int)strFileName.length() - nHeaderSize;
int dstLen = NSBase64::Base64DecodeGetRequiredLength(nBase64DataSize);
BYTE* pDstBuffer = new BYTE[dstLen];
NSBase64::Base64Decode(strFileName.c_str() + nHeaderSize, nBase64DataSize, pDstBuffer, &dstLen);
CImageFileFormatChecker checker;
std::wstring sImageExtension = checker.DetectFormatByData(pDstBuffer, dstLen);
std::wstring tempFilePath = m_strTempMedia + FILE_SEPARATOR_STR;
strFileName = NSFile::CFileBinary::CreateTempFileWithUniqueName(tempFilePath, L"img") + L"." + sImageExtension;
NSFile::CFileBinary oTempFile;
oTempFile.CreateFile(strFileName);
oTempFile.WriteFile((void*)pDstBuffer, (DWORD)dstLen);
oTempFile.CloseFile();
RELEASEARRAYOBJECTS(pDstBuffer);
}
std::wstring sMapKey = strFileName;
if(!strUrl.empty()) sMapKey = strUrl;
if(!strAdditionalFile.empty()) sMapKey += strAdditionalFile;
CMediaInfo oInfo;
std::map<std::wstring, CMediaInfo>::iterator pPair = m_mapMediaFiles.find(sMapKey);
LONG lWidth = (LONG)(dWidth * 96 / 25.4);
LONG lHeight = (LONG)(dHeight * 96 / 25.4);
if (m_mapMediaFiles.end() == pPair)
{
++m_lNextIDImage;
oInfo.m_lID = m_lNextIDImage;
LONG lImageType = m_oImageExt.GetImageType(strFileName);
bool bVector = (1 == lImageType || 2 == lImageType);
bool bOle = !strAdditionalFile.empty() && (typeAdditionalFile == 1);
bool bMedia = !strAdditionalFile.empty() && (typeAdditionalFile == 2);
if (bVector)
oInfo.m_eType = (1 == lImageType) ? itWMF : itEMF;
oInfo.SetNameModificator(oInfo.m_eType, typeAdditionalFile);
std::wstring strSaveDir = m_strDstMedia + FILE_SEPARATOR_STR;
std::wstring strSaveItemWE = strSaveDir + oInfo.GetPathWithoutExtension();
// copy ole bin or media
if (bOle || bMedia)
{
std::wstring strExts;
int nIndexExt = (int)strAdditionalFile.rfind(wchar_t('.'));
if (-1 != nIndexExt)
strExts = strAdditionalFile.substr(nIndexExt);
if(bOle && strExts.empty()) strExts = L".bin";
std::wstring sCopyOlePath = strSaveItemWE + strExts;
CDirectory::CopyFile(strAdditionalFile, sCopyOlePath);
}
if (bVector)
{
//copy source vector image
OOX::CPath pathSaveItem = strSaveDir + oInfo.GetPath2();
CDirectory::CopyFile(strFileName, pathSaveItem.GetPath());
::MetaFile::IMetaFile* pMetafile = MetaFile::Create(m_pFontManager->GetApplication());
if (pMetafile->LoadFromFile(strFileName.c_str()))
{
// пробуем сохранить в svg напрямую из метафайлов
std::wstring sInternalSvg = pMetafile->ConvertToSvg(lWidth, lHeight);
if (!sInternalSvg.empty())
{
NSFile::CFileBinary::SaveToFile(strSaveItemWE + L".svg", sInternalSvg);
m_mapMediaFiles.insert(std::make_pair(sMapKey, oInfo));
RELEASEOBJECT(pMetafile);
return oInfo;
}
// не смогли сконвертировать в svg.
// пробуем в png
std::wstring strSaveItem = strSaveItemWE + L".png";
pMetafile->ConvertToRaster(strSaveItem.c_str(), 4 /*CXIMAGE_FORMAT_PNG*/, lWidth, lHeight);
if (NSFile::CFileBinary::Exists(strSaveItem))
{
oInfo.m_eType = itPNG;
m_mapMediaFiles.insert(std::make_pair(sMapKey, oInfo));
RELEASEOBJECT(pMetafile);
return oInfo;
}
}
RELEASEOBJECT(pMetafile);
}
SaveImage(strFileName, oInfo, lWidth, lHeight);
m_mapMediaFiles.insert(std::make_pair(sMapKey, oInfo));
}
else
{
oInfo = pPair->second;
}
return oInfo;
}
CMediaInfo CMediaManager::GenerateMediaID(const std::wstring& strFileName, const std::wstring& strUrl)
{
std::wstring sMapKey;
if(!strUrl.empty()) sMapKey = strUrl;
else sMapKey = strFileName;
CMediaInfo oInfo;
std::map<std::wstring, CMediaInfo>::iterator pFind = m_mapMediaFiles.find(sMapKey);
if (m_mapMediaFiles.end() == pFind)
{
++m_lNextIDImage;
oInfo.m_lID = m_lNextIDImage;
oInfo.m_eType = itMedia;
oInfo.m_sName = L"media";
std::wstring strSaveItemWE = m_strDstMedia + FILE_SEPARATOR_STR + oInfo.GetPath2();
int nIndexExt = (int)strFileName.rfind(wchar_t('.'));
if (-1 != nIndexExt)
oInfo.m_sExt = strFileName.substr(nIndexExt);
std::wstring strCopyMediaPath = strSaveItemWE + oInfo.m_sExt;
CDirectory::CopyFile(strFileName, strCopyMediaPath);
m_mapMediaFiles.insert(std::make_pair(sMapKey, oInfo));
}
else
{
oInfo = pFind->second;
}
return oInfo;
}
MediaType CMediaManager::GetImageType(CBgraFrame& pFrame)
{
if (2 == m_lDstFormat)
return itJPG;
LONG lWidth = pFrame.get_Width();
LONG lHeight = pFrame.get_Height();
BYTE* pBuffer = pFrame.get_Data();
BYTE* pBufferMem = pBuffer + 3;
LONG lCountPix = lWidth * lHeight;
for (LONG i = 0; i < lCountPix; ++i, pBufferMem += 4)
{
if (255 != *pBufferMem)
return itPNG;
}
return itJPG;
}
void CMediaManager::FlipY(CBgraFrame& punkImage)
{
BYTE* pBuffer = punkImage.get_Data();
LONG lWidth = punkImage.get_Width();
LONG lHeight = punkImage.get_Height();
LONG lStride = punkImage.get_Stride();
if (lStride < 0)
lStride = -lStride;
if ((lWidth * 4) != lStride)
return;
BYTE* pBufferMem = new BYTE[lStride];
BYTE* pBufferEnd = pBuffer + lStride * (lHeight - 1);
LONG lCountV = lHeight / 2;
for (LONG lIndexV = 0; lIndexV < lCountV; ++lIndexV)
{
memcpy(pBufferMem, pBuffer, lStride);
memcpy(pBuffer, pBufferEnd, lStride);
memcpy(pBufferEnd, pBufferMem, lStride);
pBuffer += lStride;
pBufferEnd -= lStride;
}
RELEASEARRAYOBJECTS(pBufferMem);
}
void CMediaManager::FlipX(CBgraFrame& punkImage)
{
BYTE* pBuffer = punkImage.get_Data();
LONG lWidth = punkImage.get_Width();
LONG lHeight = punkImage.get_Height();
LONG lStride = punkImage.get_Stride();
if (lStride < 0)
lStride = -lStride;
if ((lWidth * 4) != lStride)
{
return;
}
DWORD* pBufferDWORD = (DWORD*)pBuffer;
LONG lW2 = lWidth / 2;
for (LONG lIndexV = 0; lIndexV < lHeight; ++lIndexV)
{
DWORD* pMem1 = pBufferDWORD;
DWORD* pMem2 = pBufferDWORD + lWidth - 1;
LONG lI = 0;
while (lI < lW2)
{
DWORD dwMem = *pMem1;
*pMem1++ = *pMem2;
*pMem2-- = dwMem;
}
}
}
}