763 lines
16 KiB
C++
763 lines
16 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 "BgraFrame.h"
|
|
#include "../common/File.h"
|
|
#include "../cximage/CxImage/ximage.h"
|
|
#include "ImageFileFormatChecker.h"
|
|
#include "../graphics/Image.h"
|
|
|
|
#if CXIMAGE_SUPPORT_JP2
|
|
#include "Jp2/J2kFile.h"
|
|
#include "JBig2/source/JBig2File.h"
|
|
#endif
|
|
|
|
#if CXIMAGE_SUPPORT_PIC
|
|
#include "PICT/PICFile.h"
|
|
#endif
|
|
|
|
#if CXIMAGE_SUPPORT_HEIF
|
|
#include "heif/heif.h"
|
|
#endif
|
|
|
|
#include <cmath>
|
|
#define BGRA_FRAME_CXIMAGE_MAX_MEMORY 67108864 // 256Mb (*4 channel)
|
|
|
|
void CxImageToMediaFrame( CxImage* img, CBgraFrame* bgra )
|
|
{
|
|
if( !img || !img->IsValid() )
|
|
return;
|
|
|
|
int nWidth = img->GetWidth();
|
|
int nHeight = img->GetHeight();
|
|
|
|
BYTE* pData = new BYTE[4 * nWidth * nHeight];
|
|
|
|
if (!pData)
|
|
return;
|
|
|
|
bgra->put_Data(pData);
|
|
bgra->put_Width(nWidth);
|
|
bgra->put_Height(nHeight);
|
|
bgra->put_Stride(-4 * nWidth);
|
|
|
|
BYTE* pPixels = bgra->get_Data();
|
|
|
|
int nBitsPerPixel = img->GetBpp();
|
|
int nStride = img->GetEffWidth();
|
|
BYTE* pBuffer = img->GetBits();
|
|
RGBQUAD* pPalette = img->GetPalette();
|
|
bool bIsAlphaPalettePresent = img->AlphaPaletteIsEnabled();
|
|
bool bIsAlphaApplied = false;
|
|
bool bIsRGBA = !bgra->get_IsRGBA();
|
|
|
|
if( 1 == nBitsPerPixel )
|
|
{
|
|
RGBQUAD pal[2];
|
|
|
|
if( !pPalette )
|
|
{
|
|
for( int i = 0; i < 2; i++ )
|
|
{
|
|
int c = i * 255;
|
|
pal[i].rgbBlue = c;
|
|
pal[i].rgbGreen = c;
|
|
pal[i].rgbRed = c;
|
|
}
|
|
pPalette = pal;
|
|
}
|
|
|
|
BYTE* src = pBuffer;
|
|
BYTE* dst = pPixels;
|
|
|
|
for( int nRow = 0; nRow < nHeight; ++nRow, src += nStride )
|
|
{
|
|
for( int nPos = 0; nPos < nWidth; ++nPos, dst += 4 )
|
|
{
|
|
int index = (src[nPos >> 3] >> (7 - (nPos & 7)) * 1) & 1;
|
|
dst[0] = bIsRGBA ? pPalette[index].rgbBlue : pPalette[index].rgbRed;
|
|
dst[1] = pPalette[index].rgbGreen;
|
|
dst[2] = bIsRGBA ? pPalette[index].rgbRed : pPalette[index].rgbBlue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if( 2 == nBitsPerPixel )
|
|
{
|
|
RGBQUAD pal[4];
|
|
|
|
if( !pPalette )
|
|
{
|
|
for( int i = 0; i < 4; i++ )
|
|
{
|
|
int c = (i * 255 + 2) / 3;
|
|
pal[i].rgbBlue = c;
|
|
pal[i].rgbGreen = c;
|
|
pal[i].rgbRed = c;
|
|
}
|
|
pPalette = pal;
|
|
}
|
|
|
|
BYTE* src = pBuffer;
|
|
BYTE* dst = pPixels;
|
|
|
|
for( int nRow = 0; nRow < nHeight; ++nRow, src += nStride )
|
|
{
|
|
for( int nPos = 0; nPos < nWidth; ++nPos, dst += 4 )
|
|
{
|
|
int index = (src[nPos >> 2] >> (3 - (nPos & 3)) * 2) & 3;
|
|
dst[0] = bIsRGBA ? pPalette[index].rgbBlue : pPalette[index].rgbRed;
|
|
dst[1] = pPalette[index].rgbGreen;
|
|
dst[2] = bIsRGBA ? pPalette[index].rgbRed : pPalette[index].rgbBlue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if( 4 == nBitsPerPixel )
|
|
{
|
|
RGBQUAD pal[16];
|
|
|
|
if( !pPalette )
|
|
{
|
|
for( int i = 0; i < 16; i++ )
|
|
{
|
|
int c = (i * 255 + 8) / 15;
|
|
pal[i].rgbBlue = c;
|
|
pal[i].rgbGreen = c;
|
|
pal[i].rgbRed = c;
|
|
}
|
|
pPalette = pal;
|
|
}
|
|
|
|
BYTE* src = pBuffer;
|
|
BYTE* dst = pPixels;
|
|
|
|
int nTransIndex = img->GetTransIndex();
|
|
if (bIsAlphaApplied)
|
|
nTransIndex = -1;
|
|
|
|
for( int nRow = 0; nRow < nHeight; ++nRow, src += nStride )
|
|
{
|
|
for( int nPos = 0; nPos < nWidth; ++nPos, dst += 4 )
|
|
{
|
|
int index = (src[nPos >> 1] >> (1 - (nPos & 1)) * 4) & 15;
|
|
dst[0] = bIsRGBA ? pPalette[index].rgbBlue : pPalette[index].rgbRed;
|
|
dst[1] = pPalette[index].rgbGreen;
|
|
dst[2] = bIsRGBA ? pPalette[index].rgbRed : pPalette[index].rgbBlue;
|
|
|
|
if (bIsAlphaPalettePresent)
|
|
dst[3] = pPalette[index].rgbReserved;
|
|
else if (-1 != nTransIndex)
|
|
{
|
|
if (index == nTransIndex)
|
|
dst[3] = pPalette[index].rgbReserved;
|
|
else
|
|
dst[3] = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-1 != nTransIndex || bIsAlphaPalettePresent)
|
|
bIsAlphaApplied = true;
|
|
}
|
|
else
|
|
if( 8 == nBitsPerPixel )
|
|
{
|
|
BYTE* src = pBuffer;
|
|
BYTE* dst = pPixels;
|
|
|
|
nStride -= nWidth;
|
|
|
|
int nTransIndex = img->GetTransIndex();
|
|
if (bIsAlphaApplied)
|
|
nTransIndex = -1;
|
|
|
|
if( pPalette )
|
|
{
|
|
for( int nRow = 0; nRow < nHeight; ++nRow, src += nStride )
|
|
{
|
|
for( int nPos = 0; nPos < nWidth; ++nPos, src += 1, dst += 4 )
|
|
{
|
|
int index = src[0];
|
|
dst[0] = bIsRGBA ? pPalette[index].rgbBlue : pPalette[index].rgbRed;
|
|
dst[1] = pPalette[index].rgbGreen;
|
|
dst[2] = bIsRGBA ? pPalette[index].rgbRed : pPalette[index].rgbBlue;
|
|
|
|
if (bIsAlphaPalettePresent)
|
|
dst[3] = pPalette[index].rgbReserved;
|
|
else if (-1 != nTransIndex)
|
|
{
|
|
if (index == nTransIndex)
|
|
dst[3] = pPalette[index].rgbReserved;
|
|
else
|
|
dst[3] = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-1 != nTransIndex || bIsAlphaPalettePresent)
|
|
bIsAlphaApplied = true;
|
|
}
|
|
else
|
|
{
|
|
for( int nRow = 0; nRow < nHeight; ++nRow, src += nStride )
|
|
{
|
|
for( int nPos = 0; nPos < nWidth; ++nPos, src += 1, dst += 4 )
|
|
{
|
|
int index = src[0];
|
|
dst[0] = index;
|
|
dst[1] = index;
|
|
dst[2] = index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( 24 == nBitsPerPixel )
|
|
{
|
|
BYTE* src = pBuffer;
|
|
BYTE* dst = pPixels;
|
|
|
|
nStride -= nWidth * 3;
|
|
|
|
for( int nRow = 0; nRow < nHeight; ++nRow, src += nStride )
|
|
{
|
|
for( int nPos = 0; nPos < nWidth; ++nPos, src += 3, dst += 4 )
|
|
{
|
|
dst[0] = bIsRGBA ? src[0] : src[2];
|
|
dst[1] = src[1];
|
|
dst[2] = bIsRGBA ? src[2] : src[0];
|
|
}
|
|
}
|
|
}
|
|
else if( 32 == nBitsPerPixel )
|
|
{
|
|
BYTE* src = pBuffer;
|
|
BYTE* dst = pPixels;
|
|
|
|
nStride -= nWidth * 4;
|
|
|
|
for( int nRow = 0; nRow < nHeight; ++nRow, src += nStride )
|
|
{
|
|
for( int nPos = 0; nPos < nWidth; ++nPos, src += 4, dst += 4 )
|
|
{
|
|
dst[0] = bIsRGBA ? src[0] : src[2];
|
|
dst[1] = src[1];
|
|
dst[2] = bIsRGBA ? src[2] : src[0];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bgra->Destroy();
|
|
return;
|
|
}
|
|
|
|
if( img->AlphaIsValid() )
|
|
{
|
|
BYTE* pAlpha = img->AlphaGetPointer();
|
|
DWORD nMaxAlpha = img->AlphaGetMax();
|
|
|
|
if( 255 == nMaxAlpha )
|
|
{
|
|
BYTE* src = pAlpha;
|
|
BYTE* dst = pPixels;
|
|
int nSize = nWidth * nHeight;
|
|
|
|
for( int i = 0; i < nSize; ++i, ++src, dst += 4 )
|
|
{
|
|
dst[3] = src[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BYTE table[256];
|
|
for( DWORD i = 0; i < 256; ++i )
|
|
{
|
|
DWORD a = (i * 255 + nMaxAlpha / 2) / nMaxAlpha;
|
|
table[i] = (BYTE)((a > 255) ? 255 : a);
|
|
}
|
|
|
|
BYTE* src = pAlpha;
|
|
BYTE* dst = pPixels;
|
|
int nSize = nWidth * nHeight;
|
|
|
|
for( int i = 0; i < nSize; ++i, ++src, dst += 4 )
|
|
{
|
|
dst[3] = table[src[0]];
|
|
}
|
|
}
|
|
}
|
|
else if (!bIsAlphaApplied)
|
|
{
|
|
BYTE* dst = pPixels;
|
|
int nSize = nWidth * nHeight;
|
|
|
|
for( int i = 0; i < nSize; ++i, dst += 4 )
|
|
{
|
|
dst[3] = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
CBgraFrame::CBgraFrame()
|
|
{
|
|
Clear();
|
|
}
|
|
CBgraFrame::~CBgraFrame()
|
|
{
|
|
Destroy();
|
|
}
|
|
|
|
void CBgraFrame::Destroy()
|
|
{
|
|
if (NULL != m_pData)
|
|
delete []m_pData;
|
|
|
|
if (NULL != m_pPalette)
|
|
delete []m_pPalette;
|
|
|
|
Clear();
|
|
}
|
|
void CBgraFrame::Clear()
|
|
{
|
|
m_nFileType = 0;
|
|
m_lWidth = 0;
|
|
m_lHeight = 0;
|
|
m_lStride = 0;
|
|
m_pData = NULL;
|
|
m_pPalette = NULL;
|
|
m_lPaletteColors = 0;
|
|
m_bIsGrayScale = false;
|
|
m_dJpegSaveQuality = -1;
|
|
m_bIsRGBA = false;
|
|
}
|
|
|
|
void CBgraFrame::ClearNoAttack()
|
|
{
|
|
Clear();
|
|
}
|
|
int CBgraFrame::get_Width()
|
|
{
|
|
return m_lWidth;
|
|
}
|
|
int CBgraFrame::get_Height()
|
|
{
|
|
return m_lHeight;
|
|
}
|
|
void CBgraFrame::put_Width(const int& lWidth)
|
|
{
|
|
m_lWidth = lWidth;
|
|
}
|
|
void CBgraFrame::put_Height(const int& lHeight)
|
|
{
|
|
m_lHeight = lHeight;
|
|
}
|
|
int CBgraFrame::get_Stride()
|
|
{
|
|
return m_lStride;
|
|
}
|
|
void CBgraFrame::put_Stride(const int& lStride)
|
|
{
|
|
m_lStride = lStride;
|
|
}
|
|
BYTE* CBgraFrame::get_Data()
|
|
{
|
|
return m_pData;
|
|
}
|
|
void CBgraFrame::put_Data(BYTE* pData)
|
|
{
|
|
m_pData = pData;
|
|
}
|
|
|
|
bool CBgraFrame::IsGrayScale()
|
|
{
|
|
return m_bIsGrayScale;
|
|
}
|
|
|
|
void CBgraFrame::SetJpegQuality(const double& value)
|
|
{
|
|
m_dJpegSaveQuality = value;
|
|
}
|
|
|
|
void CBgraFrame::put_IsRGBA(const bool& bIsRGBA)
|
|
{
|
|
m_bIsRGBA = bIsRGBA;
|
|
}
|
|
bool CBgraFrame::get_IsRGBA()
|
|
{
|
|
return m_bIsRGBA;
|
|
}
|
|
|
|
void CBgraFrame::put_Palette(BYTE* pDataColors, const int& colors)
|
|
{
|
|
if (!pDataColors || colors < 1) return;
|
|
|
|
if (m_pPalette)
|
|
delete []m_pPalette;
|
|
|
|
m_lPaletteColors = colors;
|
|
m_pPalette = new BYTE[colors * 4];
|
|
|
|
memcpy(m_pPalette, pDataColors, colors * 4);
|
|
}
|
|
|
|
bool CBgraFrame::OpenFile(const std::wstring& strFileName, unsigned int nFileType, const bool& bIsOrientationRemove)
|
|
{
|
|
m_nFileType = nFileType;
|
|
|
|
if (nFileType == 0)
|
|
{
|
|
CImageFileFormatChecker checker(strFileName);
|
|
m_nFileType = checker.eFileType;
|
|
}
|
|
|
|
#if CXIMAGE_SUPPORT_JP2
|
|
if (CXIMAGE_FORMAT_JP2 == m_nFileType)
|
|
{
|
|
Jpeg2000::CJ2kFile oJ2;
|
|
return oJ2.Open(this, strFileName, std::wstring(L""), !m_bIsRGBA);
|
|
}
|
|
#endif
|
|
|
|
#if CXIMAGE_SUPPORT_PIC
|
|
if (CXIMAGE_FORMAR_PIC == m_nFileType)
|
|
{
|
|
CPictFile pict_file;
|
|
return pict_file.Open(this, strFileName, m_bIsRGBA);
|
|
}
|
|
#endif
|
|
|
|
#if CXIMAGE_SUPPORT_HEIF
|
|
if (CXIMAGE_FORMAT_HEIF == m_nFileType)
|
|
{
|
|
return NSHeif::CHeifFile::Open(this, strFileName, m_bIsRGBA);
|
|
}
|
|
#endif
|
|
|
|
NSFile::CFileBinary oFile;
|
|
if (!oFile.OpenFile(strFileName))
|
|
return false;
|
|
|
|
CxImage* img = new CxImage();
|
|
|
|
if (!img->Decode(oFile.GetFileNative(), m_nFileType))
|
|
return false;
|
|
|
|
#if CXIMAGE_SUPPORT_EXIF
|
|
#if CXIMAGE_SUPPORT_TRANSFORMATION
|
|
if (bIsOrientationRemove)
|
|
img->RotateExif(0);
|
|
#endif
|
|
#endif
|
|
|
|
CxImage* imgResample = NULL;
|
|
|
|
if (false)
|
|
{
|
|
// slow!!!
|
|
int nWidth = img->GetWidth();
|
|
int nHeight = img->GetHeight();
|
|
|
|
double dSizeWH = (double)nWidth * nHeight;
|
|
double dSizeLimit = (double)BGRA_FRAME_CXIMAGE_MAX_MEMORY;
|
|
if (dSizeWH > dSizeLimit)
|
|
{
|
|
double dKoef = sqrt(dSizeLimit / dSizeWH);
|
|
int nW = (int)(dKoef * nWidth);
|
|
int nH = (int)(dKoef * nHeight);
|
|
|
|
if (nW > 10 && nH > 10)
|
|
{
|
|
imgResample = new CxImage();
|
|
if (!img->Resample(nW, nH, 2/*bicubic spline interpolation*/, imgResample))
|
|
{
|
|
delete imgResample;
|
|
imgResample = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CxImage* imageFinal = img;
|
|
if (imgResample)
|
|
{
|
|
delete img;
|
|
imageFinal = imgResample;
|
|
}
|
|
|
|
CxImageToMediaFrame(imageFinal, this);
|
|
m_bIsGrayScale = imageFinal->IsGrayScale();
|
|
delete imageFinal;
|
|
|
|
return true;
|
|
}
|
|
bool CBgraFrame::Decode(BYTE* pBuffer, int nSize, unsigned int nFileType)
|
|
{
|
|
m_nFileType = nFileType;
|
|
|
|
if (nFileType == 0)
|
|
{
|
|
CImageFileFormatChecker checker(pBuffer, nSize);
|
|
m_nFileType = checker.eFileType;
|
|
}
|
|
|
|
#if CXIMAGE_SUPPORT_JP2
|
|
if (CXIMAGE_FORMAT_JP2 == m_nFileType)
|
|
{
|
|
Jpeg2000::CJ2kFile oJ2;
|
|
return oJ2.Open(this, pBuffer, nSize, std::wstring(L""), !m_bIsRGBA);
|
|
}
|
|
#endif
|
|
|
|
#if CXIMAGE_SUPPORT_PIC
|
|
if (CXIMAGE_FORMAR_PIC == m_nFileType)
|
|
{
|
|
CPictFile pict_file;
|
|
return pict_file.Open(this, pBuffer, nSize, m_bIsRGBA);
|
|
}
|
|
#endif
|
|
|
|
#if CXIMAGE_SUPPORT_HEIF
|
|
if (CXIMAGE_FORMAT_HEIF == m_nFileType)
|
|
{
|
|
return NSHeif::CHeifFile::Open(this, pBuffer, nSize, m_bIsRGBA);
|
|
}
|
|
#endif
|
|
|
|
CxImage img;
|
|
|
|
if (!img.Decode(pBuffer, nSize, m_nFileType))
|
|
return false;
|
|
|
|
CxImageToMediaFrame(&img, this);
|
|
m_bIsGrayScale = img.IsGrayScale();
|
|
return true;
|
|
}
|
|
|
|
bool CBgraFrame::SaveFile(const std::wstring& strFileName, unsigned int nFileType)
|
|
{
|
|
uint32_t lStride = 4 * m_lWidth;
|
|
uint32_t lBitsPerPixel = 4;
|
|
if (0 != m_lStride)
|
|
{
|
|
lStride = (m_lStride > 0) ? (uint32_t)m_lStride : (uint32_t)(-m_lStride);
|
|
lBitsPerPixel = lStride / m_lWidth;
|
|
}
|
|
|
|
#if CXIMAGE_SUPPORT_JP2
|
|
if (21/*CXIMAGE_FORMAT_JBIG2*/ == nFileType)
|
|
{
|
|
CJBig2File jBig2File;
|
|
bool res = jBig2File.MemoryToJBig2(m_pData, m_lWidth * m_lHeight * 24, m_lWidth, m_lHeight, strFileName, !m_bIsRGBA);
|
|
|
|
return res;
|
|
}
|
|
#endif
|
|
#if CXIMAGE_SUPPORT_HEIF
|
|
if (CXIMAGE_FORMAT_HEIF == nFileType)
|
|
{
|
|
return NSHeif::CHeifFile::Save(m_pData, m_lWidth, m_lHeight, m_lStride, strFileName, m_bIsRGBA);
|
|
}
|
|
#endif
|
|
|
|
NSFile::CFileBinary oFile;
|
|
if (!oFile.CreateFileW(strFileName))
|
|
return false;
|
|
|
|
CxImage img;
|
|
|
|
if (!img.CreateFromArray(m_pData, m_lWidth, m_lHeight, lBitsPerPixel * 8, lStride, (m_lStride >= 0) ? true : false, !m_bIsRGBA))
|
|
return false;
|
|
|
|
if (m_pPalette)
|
|
{
|
|
img.SetPalette((RGBQUAD*)m_pPalette, m_lPaletteColors);
|
|
}
|
|
|
|
if (!img.Encode(oFile.GetFileNative(), nFileType))
|
|
return false;
|
|
|
|
oFile.CloseFile();
|
|
return true;
|
|
}
|
|
bool CBgraFrame::Encode(BYTE*& pBuffer, int& nSize, unsigned int nFileType)
|
|
{
|
|
CxImage oCxImage;
|
|
if (!oCxImage.CreateFromArray(m_pData, m_lWidth, m_lHeight, 32, 4 * m_lWidth, (m_lStride >= 0) ? true : false, !m_bIsRGBA))
|
|
return false;
|
|
|
|
if (CXIMAGE_FORMAT_JPG == nFileType && -1 != m_dJpegSaveQuality)
|
|
oCxImage.SetJpegQualityF((float)m_dJpegSaveQuality);
|
|
|
|
return oCxImage.Encode(pBuffer, nSize, nFileType);
|
|
}
|
|
void CBgraFrame::FreeEncodedMemory(void* pMemory)
|
|
{
|
|
CxImage oCxImage;
|
|
oCxImage.FreeMemory(pMemory);
|
|
}
|
|
bool CBgraFrame::Resize(const long& nNewWidth, const long& nNewHeight, bool bDestroyData)
|
|
{
|
|
CxImage img;
|
|
if (!img.CreateFromArray(m_pData, m_lWidth, m_lHeight, 32, 4 * m_lWidth, (m_lStride >= 0) ? true : false))
|
|
return false;
|
|
|
|
CxImage imgDst;
|
|
if (!img.Resample( nNewWidth, nNewHeight, 2/*bicubic spline interpolation*/, &imgDst ))
|
|
return false;
|
|
|
|
if (bDestroyData)
|
|
Destroy();
|
|
|
|
CxImageToMediaFrame( &imgDst, this );
|
|
return true;
|
|
}
|
|
bool CBgraFrame::ReColorPatternImage(const std::wstring& strFileName, unsigned int rgbColorBack, unsigned int rgbColorFore)
|
|
{
|
|
if (OpenFile(strFileName))
|
|
{
|
|
int smpl = abs(get_Stride() / get_Width());
|
|
|
|
BYTE * rgb = get_Data();
|
|
|
|
BYTE R1 = (BYTE)(rgbColorBack);
|
|
BYTE G1 = (BYTE)(rgbColorBack >> 8);
|
|
BYTE B1 = (BYTE)(rgbColorBack >> 16);
|
|
|
|
BYTE R2 = (BYTE)(rgbColorFore);
|
|
BYTE G2 = (BYTE)(rgbColorFore >> 8);
|
|
BYTE B2 = (BYTE)(rgbColorFore >> 16);
|
|
|
|
for (int i = 0 ; i < get_Width() * get_Height(); i++)
|
|
{
|
|
if (rgb[i * smpl + 0 ] == 0x00 && rgb[i * smpl + 1 ] == 0x00 && rgb[i * smpl + 2 ] == 0x00)
|
|
{
|
|
rgb[i * smpl + 0 ] = R1;
|
|
rgb[i * smpl + 1 ] = G1;
|
|
rgb[i * smpl + 2 ] = B1;
|
|
}
|
|
else
|
|
{
|
|
rgb[i * smpl + 0 ] = R2;
|
|
rgb[i * smpl + 1 ] = G2;
|
|
rgb[i * smpl + 2 ] = B2;
|
|
}
|
|
}
|
|
if (m_nFileType == 0) m_nFileType = 1;
|
|
|
|
SaveFile(strFileName, m_nFileType);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CBgraFrame::FromImage(IGrObject* pGrObject, bool bIsCopy)
|
|
{
|
|
Aggplus::CImage* pImage = (Aggplus::CImage*)pGrObject;
|
|
|
|
this->put_Width((int)pImage->GetWidth());
|
|
this->put_Height((int)pImage->GetHeight());
|
|
this->put_Stride((int)pImage->GetStride());
|
|
|
|
int nSize = 4 * m_lWidth * m_lHeight;
|
|
|
|
if (nSize > 0)
|
|
{
|
|
if (bIsCopy)
|
|
{
|
|
m_pData = new BYTE[nSize];
|
|
memcpy(m_pData, pImage->GetData(), nSize);
|
|
}
|
|
else
|
|
{
|
|
m_pData = pImage->GetData();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CBgraFrame::RemoveOrientation(const std::wstring& strFileName)
|
|
{
|
|
CImageFileFormatChecker checker(strFileName);
|
|
__ENUM_CXIMAGE_FORMATS imageType = checker.eFileType;
|
|
|
|
switch (imageType)
|
|
{
|
|
case _CXIMAGE_FORMAT_JPG:
|
|
case _CXIMAGE_FORMAT_PNG:
|
|
{
|
|
NSFile::CFileBinary oFile;
|
|
if (!oFile.OpenFile(strFileName))
|
|
return false;
|
|
|
|
CxImage* img = new CxImage();
|
|
if (!img->Decode(oFile.GetFileNative(), imageType))
|
|
{
|
|
delete img;
|
|
return false;
|
|
}
|
|
|
|
#if CXIMAGE_SUPPORT_EXIF
|
|
#if CXIMAGE_SUPPORT_TRANSFORMATION
|
|
int32_t orientation = img->GetExifInfo()->Orientation;
|
|
|
|
switch (orientation)
|
|
{
|
|
case 3:
|
|
case 6:
|
|
case 8:
|
|
case 5:
|
|
{
|
|
delete img;
|
|
oFile.CloseFile();
|
|
|
|
CBgraFrame oFrame;
|
|
oFrame.OpenFile(strFileName, imageType, true);
|
|
|
|
NSFile::CFileBinary::Remove(strFileName);
|
|
oFrame.SaveFile(strFileName, imageType);
|
|
|
|
return true;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|