mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
487 lines
12 KiB
C++
487 lines
12 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <stdio.h>
|
|
#include "MemoryUtils.h"
|
|
#include "SErrorCodes.h"
|
|
#include "SBitmap.h"
|
|
#include "File.h"
|
|
#include "StringExt.h"
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct ColorTableEntry
|
|
{
|
|
BYTE nRed;
|
|
BYTE nGreen;
|
|
BYTE nBlue;
|
|
BYTE nReserved;
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
// SBitmap
|
|
//-------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
SBitmap::SBitmap(int nWidth, int nHeight, int nRowPad, SColorMode eMode, BOOL bAlpha, BOOL bTopDown)
|
|
{
|
|
m_nWidth = nWidth;
|
|
m_nHeight = nHeight;
|
|
m_eMode = eMode;
|
|
|
|
switch ( m_eMode )
|
|
{
|
|
case colorModeMono1:
|
|
m_nStride = ( m_nWidth + 7 ) >> 3;
|
|
break;
|
|
case colorModeMono8:
|
|
m_nStride = m_nWidth;
|
|
break;
|
|
case colorModeRGB8:
|
|
case colorModeBGR8:
|
|
m_nStride = m_nWidth * 3;
|
|
break;
|
|
}
|
|
|
|
m_nStride += nRowPad - 1;
|
|
m_nStride -= m_nStride % nRowPad;
|
|
|
|
m_pData = (SColorPointer)MemUtilsMalloc( m_nStride * m_nHeight );
|
|
|
|
if ( !bTopDown )
|
|
{
|
|
m_pData += ( m_nHeight - 1 ) * m_nStride;
|
|
m_nStride = -m_nStride;
|
|
}
|
|
|
|
if ( bAlpha )
|
|
{
|
|
m_pAlpha = (unsigned char *)MemUtilsMalloc( m_nWidth * m_nHeight );
|
|
}
|
|
else
|
|
{
|
|
m_pAlpha = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
SBitmap::~SBitmap()
|
|
{
|
|
if ( m_nStride < 0 )
|
|
{
|
|
MemUtilsFree( m_pData + (m_nHeight - 1) * m_nStride );
|
|
}
|
|
else
|
|
{
|
|
MemUtilsFree( m_pData );
|
|
}
|
|
MemUtilsFree( m_pAlpha );
|
|
}
|
|
|
|
int SBitmap::WritePNMFile(wchar_t *wsFileName)
|
|
{
|
|
FILE *pFile = NULL;
|
|
SColorPointer pRow = NULL, pCurPixel = NULL;
|
|
|
|
if ( !( pFile = ::_wfopen( wsFileName, _T("wb") ) ) )
|
|
{
|
|
return SErrorOpenFile;
|
|
}
|
|
|
|
switch ( m_eMode )
|
|
{
|
|
case colorModeMono1:
|
|
fprintf( pFile, "P4\n%d %d\n", m_nWidth, m_nHeight );
|
|
pRow = m_pData;
|
|
for ( int nY = 0; nY < m_nHeight; ++nY )
|
|
{
|
|
pCurPixel = pRow;
|
|
for ( int nX = 0; nX < m_nWidth; nX += 8 )
|
|
{
|
|
fputc( *pCurPixel ^ 0xff, pFile );
|
|
++pCurPixel;
|
|
}
|
|
pRow += m_nStride;
|
|
}
|
|
break;
|
|
|
|
case colorModeMono8:
|
|
fprintf( pFile, "P5\n%d %d\n255\n", m_nWidth, m_nHeight );
|
|
pRow = m_pData;
|
|
for ( int nY = 0; nY < m_nHeight; ++nY )
|
|
{
|
|
pCurPixel = pRow;
|
|
for ( int nX = 0; nX < m_nWidth; ++nX )
|
|
{
|
|
fputc( *pCurPixel, pFile );
|
|
++pCurPixel;
|
|
}
|
|
pRow += m_nStride;
|
|
}
|
|
break;
|
|
|
|
case colorModeRGB8:
|
|
fprintf( pFile, "P6\n%d %d\n255\n", m_nWidth, m_nHeight );
|
|
pRow = m_pData;
|
|
for ( int nY = 0; nY < m_nHeight; ++nY )
|
|
{
|
|
pCurPixel = pRow;
|
|
for ( int nX = 0; nX < m_nWidth; ++nX )
|
|
{
|
|
fputc( pCurPixel[0], pFile );
|
|
fputc( pCurPixel[1], pFile );
|
|
fputc( pCurPixel[2], pFile );
|
|
pCurPixel += 3;
|
|
}
|
|
pRow += m_nStride;
|
|
}
|
|
break;
|
|
|
|
case colorModeBGR8:
|
|
fprintf( pFile, "P6\n%d %d\n255\n", m_nWidth, m_nHeight );
|
|
pRow = m_pData;
|
|
for ( int nY = 0; nY < m_nHeight; ++nY )
|
|
{
|
|
pCurPixel = pRow;
|
|
for ( int nX = 0; nX < m_nWidth; ++nX )
|
|
{
|
|
fputc( pCurPixel[2], pFile );
|
|
fputc( pCurPixel[1], pFile );
|
|
fputc( pCurPixel[0], pFile );
|
|
pCurPixel += 3;
|
|
}
|
|
pRow += m_nStride;
|
|
}
|
|
break;
|
|
}
|
|
|
|
fclose( pFile );
|
|
return SNoError;
|
|
}
|
|
|
|
int SBitmap::WriteBMPFile(wchar_t *wsFileName)
|
|
{
|
|
FILE *pFile = NULL;
|
|
int nWidth = m_nWidth;
|
|
int nHeight = m_nHeight;
|
|
SColorPointer pRow = NULL, pCurPixel = NULL;
|
|
|
|
if ( !( pFile = ::_wfopen( wsFileName, _T("wb") ) ) )
|
|
{
|
|
return SErrorOpenFile;
|
|
}
|
|
|
|
int nSize = 0, nStride;
|
|
BYTE *pBuffer = NULL, *pBufPointer;
|
|
BITMAPFILEHEADER oFileHeader;
|
|
BITMAPINFOHEADER oInfoHeader;
|
|
|
|
switch ( m_eMode )
|
|
{
|
|
case colorModeMono1:
|
|
|
|
while ( div_t(div( ( ( nWidth + 7 ) / 8 ), 4 )).rem != 0 )
|
|
{
|
|
nWidth -= 8;
|
|
if ( nWidth <= 0 )
|
|
{
|
|
return SErrorTooSmallBMP;
|
|
}
|
|
}
|
|
|
|
oFileHeader.bfType = 'M' * 256 + 'B';
|
|
oFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2 * sizeof(ColorTableEntry) + nHeight * ((nWidth + 7) / 8);
|
|
oFileHeader.bfReserved1 = 0;
|
|
oFileHeader.bfReserved2 = 0;
|
|
oFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 2 * sizeof(ColorTableEntry);
|
|
|
|
oInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
oInfoHeader.biWidth = nWidth;
|
|
oInfoHeader.biHeight = nHeight;
|
|
oInfoHeader.biPlanes = 1;
|
|
oInfoHeader.biBitCount = 1;
|
|
oInfoHeader.biCompression = BI_RGB;
|
|
oInfoHeader.biSizeImage = nHeight * ((nWidth + 7) / 8);
|
|
oInfoHeader.biXPelsPerMeter = 0;
|
|
oInfoHeader.biYPelsPerMeter = 0;
|
|
oInfoHeader.biClrUsed = 0;
|
|
oInfoHeader.biClrImportant = 0;
|
|
|
|
ColorTableEntry oFirstColor, oSecondColor;
|
|
oFirstColor.nRed = 255;
|
|
oFirstColor.nGreen = 255;
|
|
oFirstColor.nBlue = 255;
|
|
oFirstColor.nReserved = 0;
|
|
|
|
oSecondColor.nRed = 0;
|
|
oSecondColor.nGreen = 0;
|
|
oSecondColor.nBlue = 0;
|
|
oSecondColor.nReserved = 0;
|
|
|
|
::fwrite( &oFileHeader, 1, sizeof(BITMAPFILEHEADER), pFile );
|
|
::fwrite( &oInfoHeader, 1, sizeof(BITMAPINFOHEADER), pFile );
|
|
::fwrite( &oFirstColor, 1, sizeof(ColorTableEntry), pFile );
|
|
::fwrite( &oSecondColor, 1, sizeof(ColorTableEntry), pFile );
|
|
|
|
nSize = nHeight * ((nWidth + 7) / 8);
|
|
|
|
pBuffer = new BYTE[nSize];
|
|
if ( !pBuffer )
|
|
{
|
|
return SErrorMemory;
|
|
}
|
|
pBufPointer = pBuffer;
|
|
pRow = m_pData;
|
|
for ( int nY = 0; nY < nHeight; nY++ )
|
|
{
|
|
pCurPixel = pRow;
|
|
for ( int nX = 0; nX < (nWidth + 7) / 8; nX++, pBufPointer++ )
|
|
{
|
|
*pBufPointer = *pCurPixel ^ 0xff;
|
|
pCurPixel++;
|
|
}
|
|
pRow += m_nStride;
|
|
}
|
|
pBufPointer = pBuffer;
|
|
nStride = ((nWidth + 7) / 8);
|
|
pBufPointer += (nHeight - 1) * nStride;
|
|
nStride = -nStride;
|
|
|
|
for( int nRow = nHeight; nRow > 0 ; --nRow, pBufPointer += nStride )
|
|
{
|
|
::fwrite( pBufPointer, 1, abs( nStride ), pFile );
|
|
}
|
|
delete []pBuffer;
|
|
break;
|
|
|
|
case colorModeMono8:
|
|
|
|
while ( div_t(div( nWidth, 4 )).rem != 0 )
|
|
{
|
|
nWidth--;
|
|
if ( nWidth <= 0 )
|
|
{
|
|
return SErrorTooSmallBMP;
|
|
}
|
|
}
|
|
|
|
oFileHeader.bfType = 'M' * 256 + 'B';
|
|
oFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(ColorTableEntry) + nHeight * nWidth;
|
|
oFileHeader.bfReserved1 = 0;
|
|
oFileHeader.bfReserved2 = 0;
|
|
oFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + 256 * sizeof(ColorTableEntry);
|
|
|
|
oInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
oInfoHeader.biWidth = nWidth;
|
|
oInfoHeader.biHeight = nHeight;
|
|
oInfoHeader.biPlanes = 1;
|
|
oInfoHeader.biBitCount = 8;
|
|
oInfoHeader.biCompression = BI_RGB;
|
|
oInfoHeader.biSizeImage = nHeight * nWidth;
|
|
oInfoHeader.biXPelsPerMeter = 0;
|
|
oInfoHeader.biYPelsPerMeter = 0;
|
|
oInfoHeader.biClrUsed = 0;
|
|
oInfoHeader.biClrImportant = 0;
|
|
|
|
::fwrite( &oFileHeader, 1, sizeof(BITMAPFILEHEADER), pFile );
|
|
::fwrite( &oInfoHeader, 1, sizeof(BITMAPINFOHEADER), pFile );
|
|
|
|
for ( int nIndex = 0; nIndex < 256; nIndex++ )
|
|
{
|
|
ColorTableEntry oColor;
|
|
oColor.nRed = nIndex;
|
|
oColor.nGreen = nIndex;
|
|
oColor.nBlue = nIndex;
|
|
oColor.nReserved = 0;
|
|
::fwrite( &oColor, 1, sizeof(ColorTableEntry), pFile );
|
|
}
|
|
|
|
nSize = nHeight * nWidth;
|
|
|
|
pBuffer = new BYTE[nSize];
|
|
if ( !pBuffer )
|
|
{
|
|
return SErrorMemory;
|
|
}
|
|
pBufPointer = pBuffer;
|
|
pRow = m_pData;
|
|
for ( int nY = 0; nY < nHeight; nY++ )
|
|
{
|
|
pCurPixel = pRow;
|
|
for ( int nX = 0; nX < nWidth; nX++, pBufPointer++ )
|
|
{
|
|
*pBufPointer = (BYTE)*pCurPixel;
|
|
pCurPixel++;
|
|
}
|
|
pRow += m_nStride;
|
|
}
|
|
pBufPointer = pBuffer;
|
|
nStride = nWidth;
|
|
pBufPointer += (nHeight - 1) * nStride;
|
|
nStride = -nStride;
|
|
|
|
for( int nRow = nHeight; nRow > 0 ; --nRow, pBufPointer += nStride )
|
|
{
|
|
::fwrite( pBufPointer, 1, abs( nStride ), pFile );
|
|
}
|
|
delete []pBuffer;
|
|
break;
|
|
|
|
case colorModeRGB8:
|
|
case colorModeBGR8:
|
|
|
|
oFileHeader.bfType = 'M' * 256 + 'B';
|
|
oFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nHeight * nWidth * 4;
|
|
oFileHeader.bfReserved1 = 0;
|
|
oFileHeader.bfReserved2 = 0;
|
|
oFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
oInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
oInfoHeader.biWidth = nWidth;
|
|
oInfoHeader.biHeight = nHeight;
|
|
oInfoHeader.biPlanes = 1;
|
|
oInfoHeader.biBitCount = 32;
|
|
oInfoHeader.biCompression = BI_RGB;
|
|
oInfoHeader.biSizeImage = nHeight * nWidth * 4;
|
|
oInfoHeader.biXPelsPerMeter = 0;
|
|
oInfoHeader.biYPelsPerMeter = 0;
|
|
oInfoHeader.biClrUsed = 0;
|
|
oInfoHeader.biClrImportant = 0;
|
|
|
|
::fwrite( &oFileHeader, 1, sizeof(BITMAPFILEHEADER), pFile );
|
|
::fwrite( &oInfoHeader, 1, sizeof(BITMAPINFOHEADER), pFile );
|
|
|
|
nSize = nHeight * nWidth * 4;
|
|
|
|
pBuffer = new BYTE[nSize];
|
|
if ( !pBuffer )
|
|
{
|
|
return SErrorMemory;
|
|
}
|
|
pBufPointer = pBuffer;
|
|
pRow = m_pData;
|
|
for ( int nY = 0; nY < nHeight; nY++ )
|
|
{
|
|
pCurPixel = pRow;
|
|
for ( int nX = 0; nX < nWidth; nX++, pBufPointer += 4 )
|
|
{
|
|
if ( colorModeRGB8 == m_eMode )
|
|
{
|
|
pBufPointer[2] = (BYTE)pCurPixel[0];
|
|
pBufPointer[1] = (BYTE)pCurPixel[1];
|
|
pBufPointer[0] = (BYTE)pCurPixel[2];
|
|
}
|
|
else if ( colorModeBGR8 == m_eMode )
|
|
{
|
|
pBufPointer[2] = (BYTE)pCurPixel[2];
|
|
pBufPointer[1] = (BYTE)pCurPixel[1];
|
|
pBufPointer[0] = (BYTE)pCurPixel[0];
|
|
}
|
|
else
|
|
{
|
|
pBufPointer[0] = 0;
|
|
pBufPointer[1] = 0;
|
|
pBufPointer[2] = 0;
|
|
}
|
|
pBufPointer[3] = 0;
|
|
pCurPixel += 3;
|
|
}
|
|
pRow += m_nStride;
|
|
}
|
|
pBufPointer = pBuffer;
|
|
nStride = nWidth * 4;
|
|
pBufPointer += (nHeight - 1) * nStride;
|
|
nStride = -nStride;
|
|
|
|
for( int nRow = nHeight; nRow > 0 ; --nRow, pBufPointer += nStride )
|
|
{
|
|
::fwrite( pBufPointer, 1, abs( nStride ), pFile );
|
|
}
|
|
delete []pBuffer;
|
|
break;
|
|
}
|
|
|
|
fclose( pFile );
|
|
return SNoError;
|
|
}
|
|
|
|
int SBitmap::WriteJPGFile(wchar_t *wsFileName, wchar_t *wsTempFolder)
|
|
{
|
|
USES_CONVERSION;
|
|
CStringW wsTempFileName = _T("");
|
|
FILE *pTempFile = NULL;
|
|
if ( !OpenTempFile( &wsTempFileName, &pTempFile, _T("wb"), _T(".bmp"), wsTempFolder ) )
|
|
{
|
|
return SErrorTemp;
|
|
}
|
|
::fclose( pTempFile );
|
|
WriteBMPFile( wsTempFileName.GetBuffer() );
|
|
AVSImageStudio::IImageTransforms *pTransform = NULL;
|
|
CoCreateInstance( __uuidof( AVSImageStudio::ImageTransforms ), NULL, CLSCTX_INPROC_SERVER, __uuidof(AVSImageStudio::IImageTransforms), (void **)(&pTransform) );
|
|
if ( !pTransform )
|
|
return SErrorAVSImageStudio;
|
|
CString sXml("<transforms><ImageFile-LoadImage sourcepath=\"");
|
|
sXml += wsTempFileName.GetBuffer();
|
|
sXml += "\"></ImageFile-LoadImage><ImageFile-SaveAsJpeg destinationpath=\"";
|
|
sXml += wsFileName;
|
|
sXml += "\" format=\"888\" quality=\"90\"></ImageFile-SaveAsJpeg></transforms>";
|
|
BSTR bsXML = sXml.AllocSysString();
|
|
if ( !pTransform->SetXml( bsXML ) )
|
|
{
|
|
::SysFreeString( bsXML );
|
|
RELEASEINTERFACE( pTransform );
|
|
_wunlink( wsTempFileName.GetBuffer() );
|
|
return SErrorAVSImageStudio;
|
|
}
|
|
if ( !pTransform->Transform() )
|
|
{
|
|
::SysFreeString( bsXML );
|
|
RELEASEINTERFACE( pTransform );
|
|
_wunlink( wsTempFileName.GetBuffer() );
|
|
return SErrorAVSImageStudio;
|
|
}
|
|
|
|
::SysFreeString( bsXML );
|
|
RELEASEINTERFACE( pTransform );
|
|
_wunlink( wsTempFileName.GetBuffer() );
|
|
return SNoError;
|
|
}
|
|
void SBitmap::GetPixel(int nX, int nY, SColorPointer pPixel)
|
|
{
|
|
SColorPointer pColor = NULL;
|
|
|
|
if ( nY < 0 || nY >= m_nHeight || nX < 0 || nX >= m_nWidth )
|
|
{
|
|
return;
|
|
}
|
|
switch (m_eMode)
|
|
{
|
|
case colorModeMono1:
|
|
pColor = &m_pData[nY * m_nStride + (nX >> 3)];
|
|
pPixel[0] = (pColor[0] & (0x80 >> (nX & 7))) ? 0xff : 0x00;
|
|
break;
|
|
case colorModeMono8:
|
|
pColor = &m_pData[nY * m_nStride + nX];
|
|
pPixel[0] = pColor[0];
|
|
break;
|
|
case colorModeRGB8:
|
|
pColor = &m_pData[nY * m_nStride + 3 * nX];
|
|
pPixel[0] = pColor[0];
|
|
pPixel[1] = pColor[1];
|
|
pPixel[2] = pColor[2];
|
|
break;
|
|
case colorModeBGR8:
|
|
pColor = &m_pData[nY * m_nStride + 3 * nX];
|
|
pPixel[0] = pColor[2];
|
|
pPixel[1] = pColor[1];
|
|
pPixel[2] = pColor[0];
|
|
break;
|
|
}
|
|
}
|
|
|
|
unsigned char SBitmap::GetAlpha(int nX, int nY)
|
|
{
|
|
return m_pAlpha[nY * m_nWidth + nX];
|
|
}
|