Files
Yajbir Singh f1b860b25c
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++

/*
* (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;
}
}
}
}