mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-15 01:28:47 +08:00
967 lines
28 KiB
C
967 lines
28 KiB
C
#ifndef _IMAGE_H
|
|
#define _IMAGE_H
|
|
|
|
#include "Objects.h"
|
|
#include "Utils.h"
|
|
|
|
static const char *c_sColorCMYK = "DeviceCMYK";
|
|
static const char *c_sColorRGB = "DeviceRGB";
|
|
static const char *c_sColorGray = "DeviceGray";
|
|
|
|
//------------ Image âñïîìîãàòåëüíûå ôóíêöèè -----------------------------------------------------------
|
|
static unsigned long LoadJpegHeader(ImageDict pImage, Stream pStream)
|
|
{
|
|
unsigned short nTag = 0;
|
|
unsigned short nHeight = 0;
|
|
unsigned short nWidth = 0;
|
|
BYTE nPrecision;
|
|
BYTE nNumComponents;
|
|
const char *sColorSpaceName;
|
|
unsigned int nLen = 2;
|
|
unsigned long nRet = 0;
|
|
|
|
Array oArray;
|
|
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nTag, &nLen ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
UInt16Swap(&nTag);
|
|
|
|
//ïðîâåðÿåì ñèãíàòóðó: JPEG âñåãäà íà÷èíàåòñÿ ñ FFD8 è êîí÷àåòñÿ FFD9
|
|
if ( 0xFFD8 != nTag )
|
|
return AVS_OFFICEPDFWRITER_ERROR_INVALID_JPEG_DATA;
|
|
|
|
/* find SOF record */
|
|
for (;;)
|
|
{
|
|
unsigned short nSize = 0;
|
|
nLen = 2;
|
|
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nTag, &nLen) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
UInt16Swap(&nTag);
|
|
|
|
nLen = 2;
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nSize, &nLen) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
|
|
UInt16Swap(&nSize);
|
|
|
|
if ( 0xFFC0 == nTag || 0xFFC1 == nTag || 0xFFC2 == nTag || 0xFFC9 == nTag )
|
|
{
|
|
|
|
nLen = 1;
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nPrecision, &nLen) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
nLen = 2;
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nHeight, &nLen) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
UInt16Swap(&nHeight);
|
|
|
|
nLen = 2;
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nWidth, &nLen) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
UInt16Swap(&nWidth);
|
|
|
|
nLen = 1;
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nNumComponents, &nLen) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
break;
|
|
}
|
|
else if ( ( nTag | 0x00FF ) != 0xFFFF )
|
|
/* lost marker */
|
|
return SetError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_UNSUPPORTED_JPEG_FORMAT, 0);
|
|
|
|
if ( OK != StreamSeek( pStream, nSize - 2, SeekCur ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
}
|
|
|
|
if ( OK != DictAddNumber( pImage, "Height", nHeight ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
if ( OK != DictAddNumber( pImage, "Width", nWidth ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
// Êëàññèôèêàöèÿ RGB è CMYK íå ñîâåðøåííàÿ, ò.ê.
|
|
// YCbCr èëè YCCK êëàññèôèöèðóþòñÿ êàê RGB èëè CMYK.
|
|
// Íåîáõîäèìî ïðî÷èòàòü äàííûå APP14 äëÿ òî÷íîãî îïðåäåëåíèÿ
|
|
// öâåòîâîãî ïðîñòðàíñòâà.
|
|
switch ( nNumComponents )
|
|
{
|
|
case 1:
|
|
sColorSpaceName = c_sColorGray;
|
|
break;
|
|
case 3:
|
|
sColorSpaceName = c_sColorRGB;
|
|
break;
|
|
case 4:
|
|
oArray = ArrayNew( pImage->oMMgr );
|
|
if ( !oArray )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
nRet = DictAdd( pImage, "Decode", oArray );
|
|
if ( OK != nRet )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 1 ) );
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 0 ) );
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 1 ) );
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 0 ) );
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 1 ) );
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 0 ) );
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 1 ) );
|
|
nRet += ArrayAdd( oArray, NumberNew( pImage->oMMgr, 0 ) );
|
|
|
|
if ( OK != nRet )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
sColorSpaceName = c_sColorCMYK;
|
|
|
|
break;
|
|
default:
|
|
return SetError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_UNSUPPORTED_JPEG_FORMAT, 0);
|
|
}
|
|
|
|
if ( OK != DictAdd( pImage, "ColorSpace", NameNew( pImage->oMMgr, sColorSpaceName ) ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
if ( OK != DictAdd( pImage, "BitsPerComponent", NumberNew( pImage->oMMgr, nPrecision ) ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
return OK;
|
|
}
|
|
|
|
static BOOL ReadJpxBoxHeader (Stream pStream, unsigned int *punBoxType, unsigned int *punBoxLen, unsigned int *punDataLen)
|
|
{
|
|
unsigned int unLen, unLenH;
|
|
unsigned int unReadLen = 4;
|
|
|
|
if ( OK != StreamReadULong( pStream, &unLen ) || OK != StreamReadULong( pStream, punBoxType ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( 1 == unLen )
|
|
{
|
|
if ( OK != StreamReadULong( pStream, &unLenH ) || OK != StreamReadULong( pStream, &unLen ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
if ( unLenH )
|
|
{
|
|
// TO DO: Error "JPX stream contains a box larger than 2^32 bytes"
|
|
return FALSE;
|
|
}
|
|
*punBoxLen = unLen;
|
|
*punDataLen = unLen - 16;
|
|
}
|
|
else if ( 0 == unLen )
|
|
{
|
|
*punBoxLen = 0;
|
|
*punDataLen = 0;
|
|
}
|
|
else
|
|
{
|
|
*punBoxLen = unLen;
|
|
*punDataLen = unLen - 8;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int ReadJpxMarkerHeader(Stream pStream, int *pnSegmentType, unsigned int *pnSegmentLen)
|
|
{
|
|
int nChar = 0;
|
|
|
|
do
|
|
{
|
|
do
|
|
{
|
|
unsigned int nReadLen = 1;
|
|
if ( OK != StreamRead( pStream, (BYTE*)&nChar, &nReadLen ) )
|
|
return FALSE;
|
|
|
|
if ( nChar == EOF )
|
|
{
|
|
return FALSE;
|
|
}
|
|
} while ( nChar != 0xff );
|
|
do
|
|
{
|
|
unsigned int nReadLen = 1;
|
|
if ( OK != StreamRead( pStream, (BYTE*)&nChar, &nReadLen ) )
|
|
return FALSE;
|
|
|
|
if ( nChar == EOF)
|
|
{
|
|
return FALSE;
|
|
}
|
|
} while ( nChar == 0xff );
|
|
} while ( nChar == 0x00 );
|
|
*pnSegmentType = nChar;
|
|
if ( ( nChar >= 0x30 && nChar <= 0x3f ) || nChar == 0x4f || nChar == 0x92 || nChar == 0x93 || nChar == 0xd9 )
|
|
{
|
|
*pnSegmentLen = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
if ( OK != StreamReadUShort( pStream, pnSegmentLen ) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static const char* ReadJpxCodestream (Stream pStream, unsigned int *pnBitsPerComponent, unsigned int *pnWidth, unsigned int *pnHeight)
|
|
{
|
|
int nSegmentType;
|
|
unsigned int nSegmentLen;
|
|
|
|
while ( ReadJpxMarkerHeader( pStream, &nSegmentType, & nSegmentLen ) )
|
|
{
|
|
if ( 0x51 == nSegmentType )
|
|
{
|
|
unsigned int nTemp, nComponentsCount, nBPC, nXsiz, nYsiz, nXOsiz, nYOsiz;
|
|
if ( OK == StreamReadUShort( pStream, &nTemp ) && OK == StreamReadULong( pStream, &nXsiz ) && OK == StreamReadULong( pStream, &nYsiz ) &&
|
|
OK == StreamReadULong ( pStream, &nXOsiz ) && OK == StreamReadULong( pStream, &nYOsiz ) && OK == StreamReadULong( pStream, &nTemp ) &&
|
|
OK == StreamReadULong ( pStream, &nTemp ) && OK == StreamReadULong( pStream, &nTemp ) && OK == StreamReadULong( pStream, &nTemp ) &&
|
|
OK == StreamReadUShort( pStream, &nComponentsCount ) && OK == StreamReadUByte( pStream, &nBPC ) )
|
|
{
|
|
*pnBitsPerComponent = (nBPC & 0x7f) + 1;
|
|
*pnWidth = nXsiz - nXOsiz;
|
|
*pnHeight = nYsiz - nYOsiz;
|
|
|
|
if ( nComponentsCount == 1 )
|
|
{
|
|
return c_sColorGray;
|
|
}
|
|
else if ( nComponentsCount == 3 )
|
|
{
|
|
return c_sColorRGB;
|
|
}
|
|
else if ( nComponentsCount == 4 )
|
|
{
|
|
return c_sColorRGB;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
static unsigned long LoadJpxHeader (ImageDict pImage, Stream pStream, long nOpacityFlag = 0)
|
|
{
|
|
unsigned int nLen = 1;
|
|
int nChar = 10;
|
|
|
|
if ( OK != StreamRead( pStream, (BYTE *)&nChar, &nLen ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
StreamSeek( pStream, 0, SeekSet );
|
|
|
|
BOOL bHaveBPC = FALSE, bHaveModeCS = FALSE;
|
|
unsigned int nBitsPerComponent = 0;
|
|
const char *sColorSpaceName = "";
|
|
unsigned int nCSPrec = 0;
|
|
unsigned int nWidth = 0, nHeight = 0;
|
|
|
|
if ( 0xff == nChar )
|
|
{
|
|
sColorSpaceName = ReadJpxCodestream( pStream, &nBitsPerComponent, &nWidth, &nHeight );
|
|
}
|
|
else
|
|
{
|
|
unsigned int nBoxType, nBoxLen, nDataLen;
|
|
while( ReadJpxBoxHeader( pStream, &nBoxType, &nBoxLen, &nDataLen ) )
|
|
{
|
|
if ( nBoxType == 0x6a703268 ) // JP2 header
|
|
{
|
|
// íè÷åãî íå äåëàåì
|
|
}
|
|
else if ( nBoxType == 0x69686472 ) // Image header
|
|
{
|
|
unsigned int nBPC, nTemp;
|
|
if ( OK == StreamReadULong( pStream, &nTemp ) && OK == StreamReadULong( pStream, &nTemp ) && OK == StreamReadUShort( pStream, &nTemp ) &&
|
|
OK == StreamReadUByte( pStream, &nBPC ) && OK == StreamReadUByte( pStream, &nTemp ) && OK == StreamReadUByte( pStream, &nTemp ) &&
|
|
OK == StreamReadUByte( pStream, &nTemp ) )
|
|
{
|
|
nBitsPerComponent = nBPC + 1;
|
|
bHaveBPC = TRUE;
|
|
}
|
|
}
|
|
else if ( nBoxType == 0x636F6C72 ) // Color specification
|
|
{
|
|
int nMethodCS, nPrecedenceCS, nTemp;
|
|
if ( OK == StreamReadByte( pStream, &nMethodCS ) && OK == StreamReadByte( pStream, &nPrecedenceCS ) && OK == StreamReadByte( pStream, &nTemp ) )
|
|
{
|
|
if ( nMethodCS == 1 )
|
|
{
|
|
unsigned int nEnumCS;
|
|
if ( OK == StreamReadULong( pStream, &nEnumCS ) )
|
|
{
|
|
const char *sTempCS = "";
|
|
if ( nEnumCS == 0 || nEnumCS == 17 )
|
|
{
|
|
sTempCS = c_sColorGray;
|
|
}
|
|
else if ( nEnumCS == 12 )
|
|
{
|
|
sTempCS = c_sColorCMYK;
|
|
}
|
|
else if ( nEnumCS == 16 || nEnumCS == 20 || nEnumCS == 21 )
|
|
{
|
|
sTempCS = c_sColorRGB;
|
|
}
|
|
|
|
if ( strlen( sTempCS ) > 0 && ( !bHaveModeCS || nPrecedenceCS > nCSPrec ) )
|
|
{
|
|
sColorSpaceName = sTempCS;
|
|
nCSPrec = nPrecedenceCS;
|
|
bHaveModeCS = TRUE;
|
|
}
|
|
|
|
StreamSeek( pStream, nDataLen - 7, SeekCur );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
StreamSeek( pStream, nDataLen - 3, SeekCur );
|
|
}
|
|
}
|
|
}
|
|
else if ( nBoxType == 0x6A703263 ) // Codestream
|
|
{
|
|
const char* sTempCS = ReadJpxCodestream( pStream, &nBitsPerComponent, &nWidth, &nHeight );
|
|
if ( strlen( sColorSpaceName ) <= 0 )
|
|
sColorSpaceName = sTempCS;
|
|
|
|
}
|
|
else
|
|
{
|
|
StreamSeek( pStream, nDataLen, SeekCur );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( OK != DictAddNumber( pImage, "Height", nHeight ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
if ( OK != DictAddNumber( pImage, "Width", nWidth ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
// Ïî ñïåöèôèêàöèè, ColorSpace è BitsPerComponent ìîæíî îïóñòèòü, íî òîãäà äàæå AcrobatReader íå âñåãäà ïðàâèëüíî ÷èòàåò äàííûå èçîáðàæåíèÿ
|
|
if ( OK != DictAdd( pImage, "ColorSpace", NameNew( pImage->oMMgr, sColorSpaceName ) ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
if ( OK != DictAdd( pImage, "BitsPerComponent", NumberNew( pImage->oMMgr, nBitsPerComponent ) ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
// Ïðåäïîëàãàåì, ÷òî çíà÷åíèÿ nOpacityFlag ìîãóò áûòü 0, 1 èëè 2
|
|
if ( OK != DictAdd( pImage, "SMaskInData", NumberNew( pImage->oMMgr, nOpacityFlag ) ) )
|
|
return ErrorGetCode( pStream->oError );
|
|
|
|
return OK;
|
|
|
|
}
|
|
//------------ Image îñíîâíûå ôóíêöèè ------------------------------------------------------------------
|
|
ImageDict ImageLoadJpegImage (MMgr oMMgr, Stream pJpegData, Xref pXref)
|
|
{
|
|
Dict pImage;
|
|
unsigned long nRet = OK;
|
|
|
|
pImage = DictStreamNew( oMMgr, pXref );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
|
|
// Äîáàâëÿåì íåîáõîäèìûå ýëåìåíòû
|
|
pImage->nFilter = STREAM_FILTER_DCT_DECODE;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != LoadJpegHeader( pImage, pJpegData ) )
|
|
return NULL;
|
|
|
|
if ( OK != StreamSeek( pJpegData, 0, SeekSet ) )
|
|
return NULL;
|
|
|
|
for (;;)
|
|
{
|
|
BYTE pBuffer[STREAM_BUF_SIZ];
|
|
unsigned int nLen = STREAM_BUF_SIZ;
|
|
unsigned long nRet = StreamRead( pJpegData, pBuffer, &nLen );
|
|
|
|
if ( OK != nRet )
|
|
{
|
|
if ( AVS_OFFICEPDFWRITER_ERROR_STREAM_EOF == nRet )
|
|
{
|
|
if ( nLen > 0 )
|
|
{
|
|
nRet = StreamWrite( pImage->pStream, pBuffer, nLen );
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
if ( OK != StreamWrite( pImage->pStream, pBuffer, nLen ) )
|
|
return NULL;
|
|
}
|
|
|
|
return pImage;
|
|
}
|
|
|
|
ImageDict ImageLoadJpxImage (MMgr oMMgr, Stream pJpxData, Xref pXref, long nOpacityFlag)
|
|
{
|
|
Dict pImage = NULL;
|
|
unsigned long nRet = OK;
|
|
|
|
pImage = DictStreamNew( oMMgr, pXref );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
// Äîáàâëÿåì íåîáõîäèìûå ýëåìåíòû
|
|
pImage->nFilter = STREAM_FILTER_JPX_DECODE;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != LoadJpxHeader( pImage, pJpxData, nOpacityFlag ) )
|
|
return NULL;
|
|
|
|
if ( OK != StreamSeek( pJpxData, 0, SeekSet ) )
|
|
return NULL;
|
|
|
|
for (;;)
|
|
{
|
|
BYTE pBuffer[STREAM_BUF_SIZ];
|
|
unsigned int nLen = STREAM_BUF_SIZ;
|
|
unsigned long nRet = StreamRead( pJpxData, pBuffer, &nLen );
|
|
|
|
if ( OK != nRet )
|
|
{
|
|
if ( AVS_OFFICEPDFWRITER_ERROR_STREAM_EOF == nRet )
|
|
{
|
|
if ( nLen > 0 )
|
|
{
|
|
nRet = StreamWrite( pImage->pStream, pBuffer, nLen );
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
if ( OK != StreamWrite( pImage->pStream, pBuffer, nLen ) )
|
|
return NULL;
|
|
}
|
|
|
|
return pImage;
|
|
}
|
|
ImageDict ImageLoadRawImage (MMgr oMMgr, Stream pRawData, Xref pXref, unsigned int nWidth, unsigned int nHeight, ColorSpace eColorSpace)
|
|
{
|
|
unsigned long nRet = OK;
|
|
unsigned int nSize = 0;
|
|
|
|
if ( CSDeviceGray != eColorSpace && CSDeviceRGB != eColorSpace && CSDeviceCMYK != eColorSpace )
|
|
{
|
|
SetError( oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_COLOR_SPACE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
Dict pImage = DictStreamNew( oMMgr, pXref );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( CSDeviceGray == eColorSpace )
|
|
{
|
|
nSize = nWidth * nHeight;
|
|
nRet = DictAddName( pImage, "ColorSpace", c_sColorGray );
|
|
}
|
|
else if ( CSDeviceCMYK == eColorSpace )
|
|
{
|
|
nSize = nWidth * nHeight * 4;
|
|
nRet = DictAddName( pImage, "ColorSpace", c_sColorCMYK );
|
|
}
|
|
else
|
|
{
|
|
nSize = nWidth * nHeight * 3;
|
|
nRet = DictAddName( pImage, "ColorSpace", c_sColorRGB );
|
|
}
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Width", nWidth ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Height", nHeight ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "BitsPerComponent", 8 ) )
|
|
return NULL;
|
|
|
|
if ( OK != StreamWriteToStream( pRawData, pImage->pStream, 0, NULL ) )
|
|
return NULL;
|
|
|
|
if ( nSize != pImage->pStream->nSize )
|
|
{
|
|
SetError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
return pImage;
|
|
}
|
|
ImageDict ImageLoadAlphaFromMem (MMgr oMMgr, const BYTE *pBuffer, Xref pXref, unsigned int nWidth, unsigned int nHeight, unsigned int nBitsPerComponent)
|
|
{
|
|
unsigned long nRet = OK;
|
|
unsigned int nSize = 0;
|
|
|
|
if ( 1 != nBitsPerComponent && 2 != nBitsPerComponent && 4 != nBitsPerComponent && 8 != nBitsPerComponent )
|
|
{
|
|
SetError( oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
Dict pImage = DictStreamNew( oMMgr, pXref, FALSE );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
nSize = (double)nWidth * nHeight / ( 8 / nBitsPerComponent ) + 0.876;
|
|
nRet = DictAddName( pImage, "ColorSpace", c_sColorGray );
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Width", nWidth ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Height", nHeight ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "BitsPerComponent", nBitsPerComponent ) )
|
|
return NULL;
|
|
|
|
|
|
if ( OK != StreamWrite( pImage->pStream, pBuffer, nSize, true ) )
|
|
return NULL;
|
|
|
|
return pImage;
|
|
}
|
|
ImageDict ImageLoadRawImageFromMem (MMgr oMMgr, const BYTE *pBuffer, Xref pXref, unsigned int nWidth, unsigned int nHeight, ColorSpace eColorSpace, unsigned int nBitsPerComponent, BOOL bAlpha = FALSE, const BYTE *pAlphaBuffer = NULL)
|
|
{
|
|
unsigned long nRet = OK;
|
|
unsigned int nSize = 0;
|
|
|
|
if ( CSDeviceGray != eColorSpace && CSDeviceRGB != eColorSpace )
|
|
{
|
|
SetError( oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_COLOR_SPACE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
if ( 1 != nBitsPerComponent && 2 != nBitsPerComponent && 4 != nBitsPerComponent && 8 != nBitsPerComponent )
|
|
{
|
|
SetError( oMMgr->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE, 0);
|
|
return NULL;
|
|
}
|
|
|
|
Dict pImage = DictStreamNew( oMMgr, pXref, FALSE );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( CSDeviceGray == eColorSpace )
|
|
{
|
|
nSize = (double)nWidth * nHeight / ( 8 / nBitsPerComponent ) + 0.876;
|
|
nRet = DictAddName( pImage, "ColorSpace", c_sColorGray );
|
|
}
|
|
else
|
|
{
|
|
nSize = (double)nWidth * nHeight / ( 8 / nBitsPerComponent ) + 0.876;
|
|
nSize *= 3;
|
|
nRet = DictAddName( pImage, "ColorSpace", c_sColorRGB );
|
|
}
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Width", nWidth ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Height", nHeight ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "BitsPerComponent", nBitsPerComponent ) )
|
|
return NULL;
|
|
|
|
if ( bAlpha )
|
|
{
|
|
ImageDict pImageSMask = ImageLoadAlphaFromMem( oMMgr, pAlphaBuffer, pXref, nWidth, nHeight, nBitsPerComponent );
|
|
if ( !pImageSMask )
|
|
return NULL;
|
|
if ( OK != DictAdd( pImage, "SMask", pImageSMask ) )
|
|
return NULL;
|
|
#ifndef _DEBUG
|
|
pImageSMask->nFilter = STREAM_FILTER_FLATE_DECODE;
|
|
#endif
|
|
}
|
|
|
|
if ( OK != StreamWrite( pImage->pStream, pBuffer, nSize, true ) )
|
|
return NULL;
|
|
|
|
return pImage;
|
|
}
|
|
ImageDict ImageLoadJBig2Image (MMgr oMMgr, const wchar_t *wsTempFile, Xref pXref, unsigned int nWidth, unsigned int nHeight, unsigned int unImageCheckSum)
|
|
{
|
|
Dict pImage = NULL;
|
|
unsigned long nRet = OK;
|
|
|
|
pImage = DictStreamNew( oMMgr, pXref, FALSE, wsTempFile, unImageCheckSum );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
// Äîáàâëÿåì íåîáõîäèìûå ýëåìåíòû
|
|
pImage->nFilter = STREAM_FILTER_JBIG2_DECODE;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Height", nHeight ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAddNumber( pImage, "Width", nWidth ) )
|
|
return NULL;
|
|
|
|
// Ïî ñïåöèôèêàöèè, ColorSpace è BitsPerComponent ìîæíî îïóñòèòü, íî òîãäà äàæå AcrobatReader íå âñåãäà ïðàâèëüíî ÷èòàåò äàííûå èçîáðàæåíèÿ
|
|
if ( OK != DictAdd( pImage, "ColorSpace", NameNew( pImage->oMMgr, c_sColorGray ) ) )
|
|
return NULL;
|
|
|
|
if ( OK != DictAdd( pImage, "BitsPerComponent", NumberNew( pImage->oMMgr, 1 ) ) )
|
|
return NULL;
|
|
|
|
return pImage;
|
|
}
|
|
ImageDict ImageLoadJpxImage (MMgr oMMgr, const wchar_t *wsTempFile, Xref pXref, unsigned int nWidth, unsigned int nHeight, unsigned int unImageCheckSum, BOOL bAlpha = FALSE, const wchar_t *wsAlphaPath = NULL, unsigned int unAlphaCheckSum = 0)
|
|
{
|
|
Dict pImage = NULL;
|
|
unsigned long nRet = OK;
|
|
|
|
pImage = DictStreamNew( oMMgr, pXref, FALSE, wsTempFile, unImageCheckSum );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
|
|
// Äîáàâëÿåì íåîáõîäèìûå ýëåìåíòû
|
|
pImage->nFilter = STREAM_FILTER_JPX_DECODE;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
nRet += DictAddNumber( pImage, "Height", nHeight );
|
|
nRet += DictAddNumber( pImage, "Width", nWidth );
|
|
nRet += DictAddName( pImage, "ColorSpace", c_sColorRGB );
|
|
nRet += DictAddNumber( pImage, "BitsPerComponent", 8 );
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( bAlpha )
|
|
{
|
|
Dict pImageSMask = DictStreamNew( oMMgr, pXref, FALSE, wsAlphaPath, unAlphaCheckSum );
|
|
if ( !pImageSMask )
|
|
return NULL;
|
|
|
|
pImageSMask->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
pImageSMask->nFilter = STREAM_FILTER_JPX_DECODE;
|
|
nRet += DictAddName( pImageSMask, "Type", "XObject");
|
|
nRet += DictAddName( pImageSMask, "Subtype", "Image");
|
|
nRet += DictAddName( pImageSMask, "ColorSpace", c_sColorGray );
|
|
nRet += DictAddNumber( pImageSMask, "Width", nWidth );
|
|
nRet += DictAddNumber( pImageSMask, "Height", nHeight );
|
|
nRet += DictAddNumber( pImageSMask, "BitsPerComponent", 8 );
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != DictAdd( pImage, "SMask", pImageSMask ) )
|
|
return NULL;
|
|
#ifndef _DEBUG
|
|
pImageSMask->nFilter |= STREAM_FILTER_FLATE_DECODE;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if ( OK != DictAdd( pImage, "SMaskInData", NumberNew( pImage->oMMgr, 0 ) ) )
|
|
return NULL;
|
|
}
|
|
|
|
return pImage;
|
|
}
|
|
ImageDict ImageLoadJpegImage (MMgr oMMgr, const wchar_t *wsTempFile, Xref pXref, unsigned int nWidth, unsigned int nHeight, unsigned int unImageCheckSum, BOOL bAlpha = FALSE, const wchar_t *wsAlphaPath = NULL, unsigned int unAlphaCheckSum = 0)
|
|
{
|
|
Dict pImage = NULL;
|
|
unsigned long nRet = OK;
|
|
|
|
pImage = DictStreamNew( oMMgr, pXref, FALSE, wsTempFile, unImageCheckSum );
|
|
if ( !pImage )
|
|
return NULL;
|
|
|
|
pImage->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
|
|
// Äîáàâëÿåì íåîáõîäèìûå ýëåìåíòû
|
|
pImage->nFilter = STREAM_FILTER_DCT_DECODE;
|
|
nRet += DictAddName( pImage, "Type", "XObject");
|
|
nRet += DictAddName( pImage, "Subtype", "Image");
|
|
nRet += DictAddNumber( pImage, "Height", nHeight );
|
|
nRet += DictAddNumber( pImage, "Width", nWidth );
|
|
nRet += DictAddName( pImage, "ColorSpace", c_sColorRGB );
|
|
nRet += DictAddNumber( pImage, "BitsPerComponent", 8 );
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( bAlpha )
|
|
{
|
|
Dict pImageSMask = DictStreamNew( oMMgr, pXref, FALSE, wsAlphaPath, unAlphaCheckSum );
|
|
if ( !pImageSMask )
|
|
return NULL;
|
|
|
|
pImageSMask->pHeader.nObjClass |= OSUBCLASS_XOBJECT;
|
|
pImageSMask->nFilter = STREAM_FILTER_LZW_DECODE;
|
|
nRet += DictAddName( pImageSMask, "Type", "XObject");
|
|
nRet += DictAddName( pImageSMask, "Subtype", "Image");
|
|
nRet += DictAddName( pImageSMask, "ColorSpace", c_sColorGray );
|
|
nRet += DictAddNumber( pImageSMask, "Width", nWidth );
|
|
nRet += DictAddNumber( pImageSMask, "Height", nHeight );
|
|
nRet += DictAddNumber( pImageSMask, "BitsPerComponent", 8 );
|
|
|
|
if ( OK != nRet )
|
|
return NULL;
|
|
|
|
if ( OK != DictAdd( pImage, "SMask", pImageSMask ) )
|
|
return NULL;
|
|
#ifndef _DEBUG
|
|
pImageSMask->nFilter |= STREAM_FILTER_FLATE_DECODE;
|
|
#endif
|
|
}
|
|
|
|
return pImage;
|
|
}
|
|
BOOL ImageValidate (ImageDict pImage)
|
|
{
|
|
if ( !pImage )
|
|
return FALSE;
|
|
|
|
if ( pImage->pHeader.nObjClass != (OSUBCLASS_XOBJECT | OCLASS_DICT) )
|
|
{
|
|
RaiseError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE, 0);
|
|
return FALSE;
|
|
}
|
|
|
|
Name pSubtype = (Name)DictGetItem( pImage, "Subtype", OCLASS_NAME );
|
|
if ( !pSubtype || 0 != UtilsStrCmp( pSubtype->sValue, "Image" ) )
|
|
{
|
|
RaiseError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE, 0);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
TPoint ImageGetSize (ImageDict pImage)
|
|
{
|
|
TPoint oRet = {0, 0};
|
|
|
|
if ( !ImageValidate( pImage ) )
|
|
return oRet;
|
|
|
|
Number oWidth = (Number)DictGetItem( pImage, "Width", OCLASS_NUMBER );
|
|
Number oHeight = (Number)DictGetItem( pImage, "Height", OCLASS_NUMBER );
|
|
|
|
if (oWidth && oHeight)
|
|
{
|
|
oRet.fX = oWidth->nValue;
|
|
oRet.fY = oHeight->nValue;
|
|
}
|
|
|
|
return oRet;
|
|
}
|
|
unsigned long ImageGetSize2 (ImageDict pImage, TPoint *poSize)
|
|
{
|
|
poSize->fX = 0;
|
|
poSize->fY = 0;
|
|
|
|
if ( !ImageValidate( pImage ) )
|
|
return AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE;
|
|
|
|
Number oWidth = (Number)DictGetItem( pImage, "Width", OCLASS_NUMBER );
|
|
Number oHeight = (Number)DictGetItem( pImage, "Height", OCLASS_NUMBER );
|
|
|
|
if (oWidth && oHeight)
|
|
{
|
|
poSize->fX = oWidth->nValue;
|
|
poSize->fY = oHeight->nValue;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
unsigned int ImageGetBitsPerComponent(ImageDict pImage)
|
|
{
|
|
if ( !ImageValidate( pImage ) )
|
|
return 0;
|
|
|
|
Number oNumber = (Number)DictGetItem( pImage, "BitsPerComponent", OCLASS_NUMBER);
|
|
|
|
if (!oNumber)
|
|
return 0;
|
|
|
|
return oNumber->nValue;
|
|
}
|
|
const char* ImageGetColorSpace (ImageDict pImage)
|
|
{
|
|
Name oName = (Name)DictGetItem( pImage, "ColorSpace", OCLASS_NAME);
|
|
|
|
if ( !oName )
|
|
{
|
|
CheckError( pImage->oError );
|
|
return NULL;
|
|
}
|
|
|
|
return oName->sValue;
|
|
}
|
|
EColorSpace ImageGetColorSpace2 (ImageDict pImage)
|
|
{
|
|
const char* sColorSpace = ImageGetColorSpace( pImage );
|
|
|
|
if ( 0 == UtilsStrCmp( sColorSpace, c_sColorCMYK ) )
|
|
return CSDeviceCMYK;
|
|
else if ( 0 == UtilsStrCmp( sColorSpace, c_sColorRGB ) )
|
|
return CSDeviceRGB;
|
|
else if ( 0 == UtilsStrCmp( sColorSpace, c_sColorGray ) )
|
|
return CSDeviceGray;
|
|
|
|
RaiseError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_COLOR_SPACE, 0 );
|
|
return CSDeviceGray;
|
|
}
|
|
unsigned int ImageGetWidth (ImageDict pImage)
|
|
{
|
|
return ImageGetSize( pImage ).fX;
|
|
}
|
|
unsigned int ImageGetHeight (ImageDict pImage)
|
|
{
|
|
return ImageGetSize( pImage ).fY;
|
|
}
|
|
ImageDict ImageGetSMask (ImageDict pImage)
|
|
{
|
|
ImageDict oSMask = (ImageDict)DictGetItem( pImage, "SMask", OCLASS_DICT );
|
|
|
|
return oSMask;
|
|
}
|
|
unsigned long ImageSetMask (ImageDict pImage, BOOL bMask)
|
|
{
|
|
if ( !ImageValidate( pImage ) )
|
|
return AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE;
|
|
|
|
if ( bMask && 1 != ImageGetBitsPerComponent( pImage ) )
|
|
return SetError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_BIT_PER_COMPONENT, 0);
|
|
|
|
Boolean oImageMask = (Boolean)DictGetItem( pImage, "ImageMask", OCLASS_BOOLEAN);
|
|
|
|
if ( !oImageMask )
|
|
{
|
|
unsigned long nRet = OK;
|
|
oImageMask = BooleanNew( pImage->oMMgr, FALSE);
|
|
if ( OK != ( nRet = DictAdd( pImage, "ImageMask", oImageMask ) ) )
|
|
return nRet;
|
|
}
|
|
|
|
oImageMask->bValue = bMask;
|
|
return OK;
|
|
}
|
|
unsigned long ImageSetMaskImage (ImageDict pImage, ImageDict pMaskImage)
|
|
{
|
|
if ( !ImageValidate( pImage ) )
|
|
return AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE;
|
|
|
|
if ( !ImageValidate( pMaskImage ) )
|
|
return AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE;
|
|
|
|
if ( OK != ImageSetMask( pMaskImage, TRUE ) )
|
|
return CheckError( pImage->oError );
|
|
|
|
return DictAdd( pImage, "Mask", pMaskImage );
|
|
}
|
|
unsigned long ImageSetColorMask (ImageDict pImage, unsigned int nRMin, unsigned int nRMax, unsigned int nGMin, unsigned int nGMax, unsigned int nBMin, unsigned int nBMax)
|
|
{
|
|
unsigned long nRet = OK;
|
|
|
|
if ( ImageValidate( pImage ) )
|
|
return AVS_OFFICEPDFWRITER_ERROR_INVALID_IMAGE;
|
|
|
|
if ( DictGetItem( pImage, "ImageMask", OCLASS_BOOLEAN ) )
|
|
return RaiseError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_OPERATION, 0);
|
|
|
|
if ( 8 != ImageGetBitsPerComponent( pImage ) )
|
|
return RaiseError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_BIT_PER_COMPONENT, 0);
|
|
|
|
const char *sName = ImageGetColorSpace( pImage );
|
|
if ( !sName || 0 != UtilsStrCmp( c_sColorRGB, sName ) )
|
|
return RaiseError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_COLOR_SPACE, 0);
|
|
|
|
// Ëþáîå ÷èñëî äîëæíî ëåæàòü â îòðåçêå îò 0 äî 2^BitsPerComponent - 1
|
|
if ( nRMax > 255 || nGMax > 255 || nBMax > 255)
|
|
return RaiseError( pImage->oError, AVS_OFFICEPDFWRITER_ERROR_INVALID_PARAMETER, 0);
|
|
|
|
Array oArray = ArrayNew( pImage->oMMgr );
|
|
if ( !oArray )
|
|
return CheckError( pImage->oError );
|
|
|
|
nRet += DictAdd( pImage, "Mask", oArray);
|
|
nRet += ArrayAddNumber( oArray, nRMin);
|
|
nRet += ArrayAddNumber( oArray, nRMax);
|
|
nRet += ArrayAddNumber( oArray, nGMin);
|
|
nRet += ArrayAddNumber( oArray, nGMax);
|
|
nRet += ArrayAddNumber( oArray, nBMin);
|
|
nRet += ArrayAddNumber( oArray, nBMax);
|
|
|
|
if ( OK != nRet )
|
|
return CheckError( pImage->oError );
|
|
|
|
return OK;
|
|
}
|
|
#endif /* _IMAGE_H */
|
|
|