372 lines
11 KiB
C++
372 lines
11 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 "PictureDescriptor.h"
|
||
#include "OfficeDrawing/MetafilePictBlip.h"
|
||
|
||
#include "../../DesktopEditor/raster/BgraFrame.h"
|
||
|
||
#ifndef MM_ISOTROPIC
|
||
#define MM_ISOTROPIC 7
|
||
#endif
|
||
|
||
#ifndef MM_ANISOTROPIC
|
||
#define MM_ANISOTROPIC 8
|
||
#endif
|
||
|
||
namespace ImageHelper
|
||
{
|
||
Global::_BlipType SaveImageToFileFromDIB(unsigned char* data, int size, std::wstring& file_name)//without ext
|
||
{
|
||
Global::_BlipType result = Global::msoblipERROR;
|
||
|
||
CBgraFrame oFrame;
|
||
int offset = 0, biSizeImage = 0;
|
||
|
||
__BITMAPINFOHEADER * header = (__BITMAPINFOHEADER*)data;
|
||
if (!header) return result;
|
||
|
||
result = Global::msoblipDIB;
|
||
|
||
if (header->biWidth > 100000 || header->biHeight > 100000 || header->biSize != 40)
|
||
{
|
||
__BITMAPCOREHEADER * header_core = (__BITMAPCOREHEADER *)data;
|
||
if (header_core->bcSize != 12)
|
||
{
|
||
result = Global::msoblipWMF;
|
||
}
|
||
else
|
||
{
|
||
offset = 12; //sizeof(BITMAPCOREHEADER)
|
||
|
||
oFrame.put_Height (header_core->bcHeight );
|
||
oFrame.put_Width (header_core->bcWidth );
|
||
|
||
int sz_bitmap = header_core->bcHeight * header_core->bcWidth * header_core->bcBitCount/ 8;
|
||
|
||
//if (header_core->bcWidth % 2 != 0 && sz_bitmap < size - offset)
|
||
// header_core->bcWidth++;
|
||
///???? todooo непонятно .. в biff5 нужно флипать картинку, в biff8 не ясно ( -
|
||
|
||
int stride = -(size - offset) / header_core->bcHeight;
|
||
oFrame.put_Stride (stride/*header_core->bcBitCount * header_core->bcWidth /8 */);
|
||
|
||
biSizeImage = size - offset;
|
||
|
||
if (-stride >= header_core->bcWidth && header_core->bcBitCount >=24 )
|
||
{
|
||
result = Global::msoblipPNG;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
offset = 40; //sizeof(BITMAPINFOHEADER)
|
||
|
||
oFrame.put_Height (header->biHeight );
|
||
oFrame.put_Width (header->biWidth );
|
||
|
||
int sz_bitmap = header->biHeight * header->biWidth * header->biBitCount/ 8;
|
||
|
||
//if (header->biWidth % 2 != 0 && sz_bitmap < size -offset)
|
||
// header->biWidth++;
|
||
|
||
if (header->biClrUsed > 0)
|
||
{
|
||
oFrame.put_Palette((unsigned char*)data + offset, header->biClrUsed);
|
||
|
||
offset += header->biClrUsed * 4;
|
||
}
|
||
|
||
int stride = -(size - offset) / header->biHeight;
|
||
|
||
if (-stride >= header->biWidth/* && header->biBitCount >= 24*/)
|
||
{
|
||
result = Global::msoblipPNG;
|
||
}
|
||
oFrame.put_Stride(stride);
|
||
|
||
biSizeImage = header->biSizeImage > 0 ? header->biSizeImage : (size - offset);
|
||
}
|
||
|
||
//------------------------------------------------------------------------------------------
|
||
|
||
if (result == Global::msoblipPNG)
|
||
{
|
||
oFrame.put_Data((unsigned char*)data + offset);
|
||
|
||
file_name += L".png";
|
||
if (!oFrame.SaveFile(file_name, 4/*CXIMAGE_FORMAT_PNG*/))
|
||
{
|
||
result = Global::msoblipDIB;
|
||
}
|
||
oFrame.put_Data(NULL);
|
||
}
|
||
else if (result == Global::msoblipWMF)
|
||
{
|
||
file_name += L".wmf";
|
||
NSFile::CFileBinary file;
|
||
if (file.CreateFileW(file_name))
|
||
{
|
||
file.WriteFile((BYTE*)data, size);
|
||
file.CloseFile();
|
||
}
|
||
}
|
||
if (biSizeImage > 0 && result == Global::msoblipDIB)
|
||
{
|
||
file_name += L".bmp";
|
||
NSFile::CFileBinary file;
|
||
if (file.CreateFileW(file_name))
|
||
{
|
||
_UINT16 vtType = 0x4D42; file.WriteFile((BYTE*)&vtType, 2);
|
||
_UINT32 dwLen = biSizeImage; file.WriteFile((BYTE*)&dwLen, 4);
|
||
_UINT32 dwRes = 0; file.WriteFile((BYTE*)&dwRes, 4);
|
||
_UINT32 dwOffset = 2; file.WriteFile((BYTE*)&dwOffset, 4);
|
||
|
||
file.WriteFile((BYTE*)data, size);
|
||
file.CloseFile();
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
}
|
||
namespace DocFileFormat
|
||
{
|
||
/// Parses the CHPX for a fcPic an loads the PictureDescriptor at this offset
|
||
PictureDescriptor::PictureDescriptor(CharacterPropertyExceptions* chpx, POLE::Stream* stream, int size, int nWordVersion)
|
||
:
|
||
dxaGoal(0), dyaGoal(0), mx(0), my(0), Type(jpg), mfp(), dxaCropLeft(0), dyaCropTop(0),
|
||
dxaCropRight(0), dyaCropBottom(0), brcTop(NULL), brcLeft(NULL), brcBottom(NULL), brcRight(NULL), dxaOrigin(0), dyaOrigin(0),
|
||
cProps(0), shapeContainer(NULL), blipStoreEntry(NULL), embeddedData(NULL), embeddedDataSize(0), embeddedDataHeader(NULL)
|
||
{
|
||
//Get start and length of the PICT
|
||
int fc = GetFcPic( chpx );
|
||
|
||
if ( fc >= 0 )
|
||
{
|
||
parse( stream, fc, size, nWordVersion);
|
||
}
|
||
}
|
||
PictureDescriptor::PictureDescriptor()
|
||
:
|
||
dxaGoal(0), dyaGoal(0), mx(0), my(0), Type(jpg), mfp(), dxaCropLeft(0), dyaCropTop(0),
|
||
dxaCropRight(0), dyaCropBottom(0), brcTop(NULL), brcLeft(NULL), brcBottom(NULL), brcRight(NULL), dxaOrigin(0), dyaOrigin(0),
|
||
cProps(0), shapeContainer(NULL), blipStoreEntry(NULL), embeddedData(NULL), embeddedDataSize(0), embeddedDataHeader(NULL)
|
||
{
|
||
}
|
||
PictureDescriptor::~PictureDescriptor()
|
||
{
|
||
Clear();
|
||
}
|
||
void PictureDescriptor::Clear()
|
||
{
|
||
RELEASEOBJECT(brcTop);
|
||
RELEASEOBJECT(brcLeft);
|
||
RELEASEOBJECT(brcBottom);
|
||
RELEASEOBJECT(brcRight);
|
||
|
||
RELEASEOBJECT(shapeContainer);
|
||
RELEASEOBJECT(blipStoreEntry);
|
||
|
||
RELEASEARRAYOBJECTS(embeddedData);
|
||
RELEASEARRAYOBJECTS(embeddedDataHeader);
|
||
}
|
||
void PictureDescriptor::parse(POLE::Stream* stream, int fc, int sz, int nWordVersion)
|
||
{
|
||
Clear();
|
||
|
||
VirtualStreamReader reader(stream, fc, nWordVersion);
|
||
|
||
int sz_stream = reader.GetSize();
|
||
|
||
int lcb = reader.ReadInt32();
|
||
|
||
int pos_start = reader.GetPosition();
|
||
|
||
if (lcb > 10000000)
|
||
return;
|
||
|
||
if (lcb > sz && sz != 1 && sz != 2) //bullet picture с неверным размером
|
||
{
|
||
unsigned char* bytes = reader.ReadBytes(sz - fc - 4, false);
|
||
if ( bytes )
|
||
{
|
||
RELEASEARRAYOBJECTS( bytes );
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (lcb < 10)
|
||
return;
|
||
|
||
int cbHeader = reader.ReadUInt16();
|
||
|
||
mfp.mm = reader.ReadInt16();
|
||
mfp.xExt = reader.ReadInt16();
|
||
mfp.yExt = reader.ReadInt16();
|
||
mfp.hMf = reader.ReadInt16();
|
||
|
||
unsigned char* bytes = reader.ReadBytes(14, true);
|
||
rcWinMf = std::vector<unsigned char>(bytes, (bytes + 14));
|
||
RELEASEARRAYOBJECTS(bytes);
|
||
|
||
//dimensions
|
||
dxaGoal = reader.ReadInt16();
|
||
dyaGoal = reader.ReadInt16();
|
||
mx = reader.ReadUInt16();
|
||
my = reader.ReadUInt16();
|
||
|
||
//cropping
|
||
dxaCropLeft = reader.ReadInt16();
|
||
dyaCropTop = reader.ReadInt16();
|
||
dxaCropRight = reader.ReadInt16();
|
||
dyaCropBottom = reader.ReadInt16();
|
||
|
||
int brcl = reader.ReadInt16();
|
||
|
||
// borders
|
||
int bytesCount = (nWordVersion > 0) ? 2 : 4;
|
||
|
||
bytes = reader.ReadBytes( bytesCount, true );
|
||
brcTop = new BorderCode( bytes, bytesCount );
|
||
RELEASEARRAYOBJECTS( bytes );
|
||
|
||
bytes = reader.ReadBytes( bytesCount, true );
|
||
brcLeft = new BorderCode( bytes, bytesCount );
|
||
RELEASEARRAYOBJECTS( bytes );
|
||
|
||
bytes = reader.ReadBytes( bytesCount, true );
|
||
brcBottom = new BorderCode( bytes, bytesCount );
|
||
RELEASEARRAYOBJECTS( bytes );
|
||
|
||
bytes = reader.ReadBytes( bytesCount, true );
|
||
brcRight = new BorderCode( bytes, bytesCount );
|
||
RELEASEARRAYOBJECTS( bytes );
|
||
|
||
dxaOrigin = reader.ReadInt16();
|
||
dyaOrigin = reader.ReadInt16();
|
||
|
||
int pos_end = reader.GetPosition();
|
||
if (nWordVersion > 0)
|
||
{
|
||
int flag = brcl;
|
||
|
||
brcl = FormatUtils::BitmaskToBool(flag, 0x000F);
|
||
//( 0 single 1 thick 2 double 3 shadow )
|
||
|
||
bool fFrameEmpty = FormatUtils::BitmaskToBool(flag, 0x0010);// picture consists of a single frame
|
||
bool fBitmap = FormatUtils::BitmaskToBool(flag, 0x0020);// ==1, when picture is just a bitmap
|
||
bool fDrawHatch = FormatUtils::BitmaskToBool(flag, 0x0040);// ==1, when picture is an active OLE object
|
||
bool fError = FormatUtils::BitmaskToBool(flag, 0x0080);// ==1, when picture is just an error message
|
||
short bpp = FormatUtils::BitmaskToBool(flag, 0x8000);// bits per pixel
|
||
//(0 unknown 1 monochrome 4 VGA)
|
||
|
||
int sz_hdr = pos_end - pos_start;
|
||
|
||
int header_size = 114;
|
||
|
||
embeddedDataSize = lcb - sz_hdr - header_size;
|
||
embeddedDataHeader = reader.ReadBytes( header_size, true);
|
||
embeddedData = reader.ReadBytes( embeddedDataSize, true );
|
||
}
|
||
else
|
||
{
|
||
cProps = reader.ReadInt16();
|
||
|
||
if (mfp.mm == MM_SHAPEFILE)
|
||
{
|
||
unsigned char cchPicName = reader.ReadByte();
|
||
unsigned char* stPicName = reader.ReadBytes(cchPicName, true);
|
||
|
||
if ( stPicName != NULL )
|
||
{
|
||
std::wstring picName;
|
||
FormatUtils::GetWStringFromBytes( picName, stPicName, cchPicName, ENCODING_WINDOWS_1250 );
|
||
RELEASEARRAYOBJECTS(stPicName);
|
||
}
|
||
}
|
||
|
||
shapeContainer = dynamic_cast<ShapeContainer*>(RecordFactory::ReadRecord(&reader, 0));
|
||
|
||
long pos = reader.GetPosition();
|
||
|
||
if( pos < ( fc + lcb ))
|
||
{
|
||
Record* rec = RecordFactory::ReadRecord( &reader, 0 );
|
||
|
||
if ((rec) && ( typeid(*rec) == typeid(BlipStoreEntry) ))
|
||
{
|
||
blipStoreEntry = dynamic_cast<BlipStoreEntry*>( rec );
|
||
}
|
||
else
|
||
{
|
||
RELEASEOBJECT(rec);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Returns the fcPic into the "data" stream, where the PIC begins.
|
||
/// Returns -1 if the CHPX has no fcPic.
|
||
int PictureDescriptor::GetFcPic(const CharacterPropertyExceptions* chpx)
|
||
{
|
||
int ret = -1, ret1 = -1;
|
||
|
||
for ( std::vector<SinglePropertyModifier>::const_iterator iter = chpx->grpprl->begin(); iter != chpx->grpprl->end(); iter++ )
|
||
{
|
||
switch ( iter->OpCode )
|
||
{
|
||
case sprmOldCPicLocation:
|
||
case sprmCPicLocation:
|
||
ret = FormatUtils::BytesToInt32( iter->Arguments, 0, iter->argumentsSize );
|
||
break;
|
||
|
||
case sprmOldCHps:
|
||
case sprmCHps:
|
||
ret1 = FormatUtils::BytesToInt32( iter->Arguments, 0, iter->argumentsSize );
|
||
break;
|
||
|
||
case sprmCHsp:
|
||
ret = FormatUtils::BytesToInt32( iter->Arguments, 0, iter->argumentsSize );
|
||
break;
|
||
|
||
case sprmOldCFData:
|
||
case sprmCFData:
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
} |