1939 lines
46 KiB
C++
1939 lines
46 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 "PICFile.h"
|
|
#include "../../common/File.h"
|
|
|
|
#include <sys/stat.h>
|
|
#ifndef _WIN32
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
CPictFile::CPictFile()
|
|
{
|
|
m_pRenderer = NSGraphics::Create();
|
|
m_pFontManager = NSFonts::NSFontManager::Create();
|
|
m_pRenderer->SetFontManager(m_pFontManager);
|
|
}
|
|
|
|
CPictFile::~CPictFile()
|
|
{
|
|
RELEASEINTERFACE(m_pFontManager);
|
|
RELEASEINTERFACE(m_pRenderer);
|
|
}
|
|
|
|
bool CPictFile::Open(CBgraFrame* frame, const std::wstring& fileName, bool isRGB)
|
|
{
|
|
NSFile::CFileBinary file;
|
|
if (!file.OpenFile(fileName))
|
|
return false;
|
|
|
|
m_pFile = file.GetFileNative();
|
|
auto status = Decode();
|
|
file.CloseFile();
|
|
|
|
if (!status)
|
|
return false;
|
|
|
|
BYTE* data = new BYTE[4 * m_oImgData.m_nWidth * m_oImgData.m_nHeight];
|
|
frame->put_Data(data);
|
|
frame->put_Height(m_oImgData.m_nHeight);
|
|
frame->put_Width(m_oImgData.m_nWidth);
|
|
frame->put_Stride(4 * m_oImgData.m_nWidth);
|
|
|
|
BYTE* buffer = data;
|
|
|
|
for (size_t i = 0; i < m_oImgData.m_nHeight; i++)
|
|
{
|
|
BYTE* q = m_oImgData.m_pPixelData + 4 * i * m_oImgData.m_nWidth;
|
|
for (size_t j = 0; j < m_oImgData.m_nWidth; j++)
|
|
{
|
|
buffer[isRGB ? 0 : 2] = * q;
|
|
buffer[1] = * (q + 1);
|
|
buffer[isRGB ? 2 : 0] = * (q + 2);
|
|
buffer[3] = *(q + 3);
|
|
q += 4;
|
|
buffer += 4;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CPictFile::Open(CBgraFrame* frame, BYTE* buffer, const size_t& size, bool isRGB)
|
|
{
|
|
NSFile::CFileBinary file;
|
|
auto tmp_file = NSFile::CFileBinary::CreateTempFileWithUniqueName(NSFile::CFileBinary::GetTempPath(), L"pct");
|
|
|
|
if (tmp_file.empty())
|
|
return false;
|
|
|
|
if (!file.CreateFile(tmp_file))
|
|
return false;
|
|
|
|
file.WriteFile(buffer, size);
|
|
file.CloseFile();
|
|
|
|
return Open(frame, tmp_file, isRGB);
|
|
}
|
|
|
|
bool CPictFile::Decode()
|
|
{
|
|
if (m_pFile == nullptr)
|
|
return 0;
|
|
|
|
if (!DecodeHeader())
|
|
return false;
|
|
|
|
if (feof(m_pFile) != 0)
|
|
return false;
|
|
|
|
return DecodeData();
|
|
}
|
|
|
|
bool CPictFile::DecodeHeader()
|
|
{
|
|
unsigned char header[4];
|
|
|
|
Aggplus::Rect rect;
|
|
|
|
Read(4, header);
|
|
|
|
if (!((header[0] == 0x50) && (header[1] == 0x49) && (header[2] == 0x43) && (header[3] == 0x54 )))
|
|
{
|
|
rect.Y = (short) ((header[2] << 8) | header[3]);
|
|
rect.X = ReadShortValue();
|
|
rect.Height = ReadShortValue() - rect.Y;
|
|
rect.Width = ReadShortValue() - rect.X;
|
|
|
|
if (!rect.IsPositive())
|
|
return false;
|
|
|
|
m_oImgData.m_nWidth = rect.Width;
|
|
m_oImgData.m_nHeight = rect.Height;
|
|
|
|
fseek(m_pFile, 1, SEEK_CUR);
|
|
if (fgetc(m_pFile) == 0x11)
|
|
{
|
|
if (fgetc(m_pFile) == 2)
|
|
{
|
|
if (fgetc(m_pFile) != 0xff)
|
|
return false;
|
|
m_nVersion = 2;
|
|
}
|
|
else
|
|
m_nVersion = 1;
|
|
|
|
return true;
|
|
}
|
|
|
|
fseek(m_pFile, 512, SEEK_SET);
|
|
fseek(m_pFile, 2, SEEK_CUR);
|
|
if (!ReadRectangle(&rect))
|
|
return false;
|
|
|
|
if (!rect.IsPositive())
|
|
return false;
|
|
|
|
m_oImgData.m_nWidth = rect.Width;
|
|
m_oImgData.m_nHeight = rect.Height;
|
|
|
|
fseek(m_pFile, 1, SEEK_CUR);
|
|
if (fgetc(m_pFile) == 0x11)
|
|
{
|
|
int version = fgetc(m_pFile);
|
|
if (version == 2)
|
|
{
|
|
if (fgetc(m_pFile) != 0xff)
|
|
return false;
|
|
|
|
m_nVersion = 2;
|
|
}
|
|
else if (version == 1)
|
|
m_nVersion = 1;
|
|
else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CPictFile::DecodeData()
|
|
{
|
|
int flag = 0;
|
|
|
|
bool is_pix_data = false;
|
|
if (!m_oImgData.m_pPixelData)
|
|
{
|
|
m_oImgData.m_pPixelData = (BYTE*) malloc(m_oImgData.m_nWidth * m_oImgData.m_nHeight * 4);
|
|
memset(m_oImgData.m_pPixelData, 255, m_oImgData.m_nWidth * m_oImgData.m_nHeight * 4);
|
|
}
|
|
|
|
for (int code = 0; feof(m_pFile) == 0; )
|
|
{
|
|
if (m_nVersion == 1 || ftell(m_pFile) % 2 != 0)
|
|
code = fgetc(m_pFile);
|
|
if (m_nVersion == 2)
|
|
code = ReadSignedShortValue();
|
|
code &= 0xffff;
|
|
if (code < 0)
|
|
break;
|
|
if (code == 0)
|
|
continue;
|
|
if (code <= 0xa1)
|
|
{
|
|
switch(code)
|
|
{
|
|
case 0x01:
|
|
{
|
|
size_t length = ReadShortValue();
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
if (length != 0x000a)
|
|
{
|
|
for (size_t i = 0; i < length - 2; i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
break;
|
|
}
|
|
|
|
Aggplus::Rect frame;
|
|
if (ReadRectangle(&frame) == 0)
|
|
return false;
|
|
if (((frame.GetLeft() & 0x8000) != 0) || ((frame.GetTop() & 0x8000) != 0))
|
|
break;
|
|
|
|
m_oImgData.Realloc(frame.Width, frame.Height);
|
|
break;
|
|
}
|
|
case 0x11:
|
|
{
|
|
fseek(m_pFile, 1, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x08:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0xa0:
|
|
{
|
|
fseek(m_pFile, 2, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x1d:
|
|
case 0x1f:
|
|
{
|
|
fseek(m_pFile, 3, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x06:
|
|
case 0x0b:
|
|
case 0x0c:
|
|
case 0x0f:
|
|
case 0x6d:
|
|
case 0x6e:
|
|
case 0x6f:
|
|
{
|
|
fseek(m_pFile, 4, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x02:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x10:
|
|
case 0x35:
|
|
case 0x36:
|
|
case 0x37:
|
|
case 0x45:
|
|
case 0x46:
|
|
case 0x47:
|
|
case 0x55:
|
|
case 0x56:
|
|
case 0x57:
|
|
{
|
|
fseek(m_pFile, 8, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x2d:
|
|
{
|
|
fseek(m_pFile, 10, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x65:
|
|
case 0x66:
|
|
case 0x67:
|
|
{
|
|
fseek(m_pFile, 12, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0xa1:
|
|
{
|
|
fseek(m_pFile, 2, SEEK_CUR);
|
|
size_t length = ReadShortValue();
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
fseek(m_pFile, length, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x24:
|
|
case 0x25:
|
|
case 0x26:
|
|
case 0x27:
|
|
case 0x2e:
|
|
case 0x2f:
|
|
case 0x75:
|
|
case 0x76:
|
|
case 0x77:
|
|
case 0x80:
|
|
case 0x81:
|
|
case 0x82:
|
|
case 0x83:
|
|
case 0x84:
|
|
case 0x92:
|
|
case 0x93:
|
|
case 0x94:
|
|
case 0x95:
|
|
case 0x96:
|
|
case 0x97:
|
|
case 0x9c:
|
|
case 0x9d:
|
|
case 0x9e:
|
|
case 0x9f:
|
|
{
|
|
size_t length = ReadShortValue();
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
fseek(m_pFile, length - 2, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x85:
|
|
case 0x86:
|
|
case 0x87:
|
|
{
|
|
size_t length = ReadShortValue();
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
fseek(m_pFile, length - 4, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x04:
|
|
{
|
|
char c = fgetc(m_pFile);
|
|
if ((c & 0x01) != 0)
|
|
m_nFontStyle |= 0x01;
|
|
if ((c & 0x02) != 0)
|
|
m_nFontStyle |= 0x02;
|
|
if ((c & 0x04) != 0)
|
|
m_nFontStyle |= 0x7c >> 2;
|
|
if ((c & 0x08) != 0)
|
|
m_nFontStyle |= 0x0180 >> 7;
|
|
break;
|
|
}
|
|
case 0x07:
|
|
{
|
|
m_nPenHeight = ReadShortValue();
|
|
m_nPenWidth = ReadShortValue();
|
|
break;
|
|
}
|
|
case 0x0d:
|
|
{
|
|
m_nFontSize = ReadShortValue();
|
|
break;
|
|
}
|
|
case 0x0e:
|
|
{
|
|
long color = ReadLongValue();
|
|
|
|
switch(color)
|
|
{
|
|
case 33: m_pRenderer->put_BrushColor1(0x000000); break;
|
|
case 30: m_pRenderer->put_BrushColor1(0xFFFFFF); break;
|
|
case 205: m_pRenderer->put_BrushColor1(0xFF8080); break; //lightred
|
|
case 341: m_pRenderer->put_BrushColor1(0x90EE90); break; //lightgreen
|
|
case 409: m_pRenderer->put_BrushColor1(0xADD8E6); break; //lightblue
|
|
case 273: m_pRenderer->put_BrushColor1(0xE0FFFF); break; //lightcyan
|
|
case 137: m_pRenderer->put_BrushColor1(0xFF80FF); break; //lightmagenta
|
|
case 69: m_pRenderer->put_BrushColor1(0xFFFF00); break; //yellow
|
|
default: m_pRenderer->put_BrushColor1(0xD3D3D3); break; //lightgray
|
|
}
|
|
break;
|
|
}
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
{
|
|
short pattern = ReadShortValue();
|
|
for (size_t i = 0; i < 8; i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
if (pattern == 2)
|
|
{
|
|
for (size_t i = 0; i < 5; i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
break;
|
|
}
|
|
if (pattern != 1)
|
|
return false;
|
|
|
|
size_t length = ReadShortValue();
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
Aggplus::Rect frame;
|
|
if (ReadRectangle(&frame) == 0)
|
|
return false;
|
|
|
|
fseek(m_pFile, 18, SEEK_CUR);
|
|
|
|
short bits_per_pixel = ReadShortValue();
|
|
short component_count = ReadShortValue();
|
|
short component_size = ReadShortValue();
|
|
|
|
fseek(m_pFile, 12, SEEK_CUR);
|
|
|
|
if (feof(m_pFile) != 0 || bits_per_pixel <= 0 ||
|
|
bits_per_pixel > 32 || component_count <= 0 ||
|
|
component_count > 4 || component_size <= 0)
|
|
return false;
|
|
|
|
fseek(m_pFile, 4, SEEK_CUR);
|
|
flag = ReadShortValue();
|
|
length = ReadShortValue();
|
|
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < length; i++)
|
|
fseek(m_pFile, 4, SEEK_CUR);
|
|
|
|
size_t width = frame.Width;
|
|
size_t height = frame.Height;
|
|
|
|
if (bits_per_pixel <= 8)
|
|
length &= 0x7fff;
|
|
|
|
if (bits_per_pixel == 16)
|
|
width <<= 1;
|
|
|
|
if (length == 0)
|
|
length = width;
|
|
|
|
if (length < 8)
|
|
{
|
|
for (size_t i = 0; i < (length * height); i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < height; i++)
|
|
{
|
|
size_t scanline_length;
|
|
|
|
if (feof(m_pFile) != 0)
|
|
break;
|
|
|
|
if (length > 200)
|
|
scanline_length = ReadShortValue();
|
|
else
|
|
scanline_length = fgetc(m_pFile);
|
|
|
|
if (scanline_length > GetFileSize())
|
|
return false;
|
|
|
|
for (size_t j = 0; j < scanline_length; j++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case 0x1a:
|
|
{
|
|
BYTE r = ReadShortValue() >> 8;
|
|
BYTE g = ReadShortValue() >> 8;
|
|
BYTE b = ReadShortValue() >> 8;
|
|
long c = r << 16 | g << 8 | b;
|
|
m_pRenderer->put_BrushColor1(c);
|
|
break;
|
|
}
|
|
case 0x1b:
|
|
{
|
|
fseek(m_pFile, 6, SEEK_CUR);
|
|
break;
|
|
}
|
|
case 0x20:
|
|
{
|
|
short y1 = ReadShortValue();
|
|
short x1 = ReadShortValue();
|
|
short y2 = ReadShortValue();
|
|
short x2 = ReadShortValue();
|
|
|
|
m_oPenPoint = Aggplus::Point(x2, y2);
|
|
|
|
if (m_nPenHeight == 0 && m_nPenWidth == 0)
|
|
break;
|
|
|
|
DrawLine(Aggplus::Point(x1, y1), Aggplus::Point(x2, y2));
|
|
break;
|
|
}
|
|
case 0x21:
|
|
{
|
|
short y1 = ReadShortValue();
|
|
short x1 = ReadShortValue();
|
|
|
|
if (feof(m_pFile))
|
|
break;
|
|
|
|
if (m_nPenHeight == 0 && m_nPenWidth == 0)
|
|
break;
|
|
|
|
DrawLine(Aggplus::Point(x1, y1), m_oPenPoint);
|
|
break;
|
|
}
|
|
case 0x22:
|
|
{
|
|
short y1 = ReadShortValue();
|
|
short x1 = ReadShortValue();
|
|
short y2 = static_cast<short>(y1 + fgetc(m_pFile));
|
|
short x2 = static_cast<short>(x1 + fgetc(m_pFile));
|
|
|
|
if (m_nPenHeight == 0 && m_nPenWidth == 0)
|
|
break;
|
|
|
|
DrawLine(Aggplus::Point(x1, y1), Aggplus::Point(x2, y2));
|
|
break;
|
|
}
|
|
case 0x23:
|
|
{
|
|
short y2 = static_cast<short>(m_oPenPoint.Y + fgetc(m_pFile));
|
|
short x2 = static_cast<short>(m_oPenPoint.X + fgetc(m_pFile));
|
|
|
|
if (m_nPenHeight == 0 && m_nPenWidth == 0)
|
|
break;
|
|
|
|
DrawLine(m_oPenPoint, Aggplus::Point(x2, y2));
|
|
break;
|
|
}
|
|
case 0x28:
|
|
{
|
|
short y = ReadShortValue();
|
|
short x = ReadShortValue();
|
|
|
|
m_oTextPoint = Aggplus::Point(x, y);
|
|
ReadAndDrawText(x, y);
|
|
break;
|
|
}
|
|
case 0x29:
|
|
{
|
|
unsigned char h = static_cast<unsigned char>(fgetc(m_pFile));
|
|
ReadAndDrawText(m_oTextPoint.X + h, m_oTextPoint.Y);
|
|
break;
|
|
}
|
|
case 0x2a:
|
|
{
|
|
unsigned char v = static_cast<unsigned char>(fgetc(m_pFile));
|
|
ReadAndDrawText(m_oTextPoint.X, m_oTextPoint.Y + v);
|
|
break;
|
|
}
|
|
case 0x2b:
|
|
{
|
|
unsigned char h = static_cast<unsigned char>(fgetc(m_pFile));
|
|
unsigned char v = static_cast<unsigned char>(fgetc(m_pFile));
|
|
ReadAndDrawText(m_oTextPoint.X + h, m_oTextPoint.Y + v);
|
|
break;
|
|
}
|
|
case 0x2c:
|
|
{
|
|
fseek(m_pFile, 4, SEEK_CUR);
|
|
char byte_len = fgetc(m_pFile);
|
|
unsigned short len = static_cast<unsigned short>(byte_len) & 0x00ff;
|
|
char f_name[256];
|
|
Read(len, f_name);
|
|
f_name[len] = 0;
|
|
m_wsFontName = std::wstring(len, L'\0');
|
|
std::mbstowcs(&m_wsFontName[0], f_name, len);
|
|
break;
|
|
}
|
|
case 0x30:
|
|
case 0x31:
|
|
case 0x32:
|
|
case 0x33:
|
|
case 0x34:
|
|
{
|
|
if (!ReadRectangle(&m_oLastRect))
|
|
break;
|
|
|
|
DrawRect(code == 0x30);
|
|
break;
|
|
}
|
|
case 0x38:
|
|
case 0x39:
|
|
case 0x3a:
|
|
case 0x3b:
|
|
case 0x3c:
|
|
{
|
|
DrawRect(code == 0x38);
|
|
break;
|
|
}
|
|
case 0x40:
|
|
case 0x41:
|
|
case 0x42:
|
|
case 0x43:
|
|
case 0x44:
|
|
{
|
|
if (!ReadRectangle(&m_oLastRoundRect))
|
|
break;
|
|
|
|
DrawRoundRect(code == 0x40);
|
|
break;
|
|
}
|
|
case 0x48:
|
|
case 0x49:
|
|
case 0x4a:
|
|
case 0x4b:
|
|
case 0x4c:
|
|
{
|
|
DrawRoundRect(code == 0x48);
|
|
break;
|
|
}
|
|
case 0x50:
|
|
case 0x51:
|
|
case 0x52:
|
|
case 0x53:
|
|
case 0x54:
|
|
{
|
|
if (!ReadRectangle(&m_oLastOval))
|
|
break;
|
|
|
|
DrawOval(code == 0x50);
|
|
break;
|
|
}
|
|
case 0x58:
|
|
case 0x59:
|
|
case 0x5a:
|
|
case 0x5b:
|
|
case 0x5c:
|
|
{
|
|
DrawOval(code == 0x58);
|
|
break;
|
|
}
|
|
case 0x60:
|
|
case 0x61:
|
|
case 0x62:
|
|
case 0x63:
|
|
case 0x64:
|
|
{
|
|
if (!ReadRectangle(&m_oLastArc))
|
|
break;
|
|
|
|
DrawArc();
|
|
break;
|
|
}
|
|
case 0x68:
|
|
case 0x69:
|
|
case 0x6a:
|
|
case 0x6b:
|
|
case 0x6c:
|
|
{
|
|
DrawArc();
|
|
break;
|
|
}
|
|
case 0x70:
|
|
case 0x71:
|
|
case 0x72:
|
|
case 0x73:
|
|
case 0x74:
|
|
{
|
|
ReadPolygon();
|
|
DrawPolygon(code == 0x70);
|
|
break;
|
|
}
|
|
case 0x78:
|
|
case 0x79:
|
|
case 0x7a:
|
|
case 0x7b:
|
|
case 0x7c:
|
|
{
|
|
DrawPolygon(code == 0x78);
|
|
break;
|
|
}
|
|
case 0x90:
|
|
case 0x91:
|
|
case 0x98:
|
|
case 0x99:
|
|
case 0x9a:
|
|
case 0x9b:
|
|
{
|
|
is_pix_data = true;
|
|
short bits_per_pixel = 0;
|
|
short component_count = 0;
|
|
|
|
size_t bytes_per_line = 0;
|
|
if ((code != 0x9a) && (code != 0x9b))
|
|
bytes_per_line = ReadShortValue();
|
|
else
|
|
fseek(m_pFile, 6, SEEK_CUR);
|
|
|
|
Aggplus::Rect frame;
|
|
if (ReadRectangle(&frame) == 0)
|
|
return false;
|
|
|
|
Image tile_image(m_oImgData);
|
|
if (frame.Width != 0)
|
|
tile_image.m_nWidth = frame.Width;
|
|
if (frame.Height != 0)
|
|
tile_image.m_nHeight = frame.Height;
|
|
|
|
tile_image.m_pPixelData = (BYTE*)malloc(4 * tile_image.m_nWidth * tile_image.m_nHeight);
|
|
if ((code == 0x9a) || (code == 0x9b) || ((bytes_per_line & 0x8000) != 0))
|
|
{
|
|
fseek(m_pFile, 18, SEEK_CUR);
|
|
|
|
bits_per_pixel = ReadShortValue();
|
|
component_count = ReadShortValue();
|
|
short component_size = ReadShortValue();
|
|
|
|
fseek(m_pFile, 12, SEEK_CUR);
|
|
|
|
if (feof(m_pFile) != 0 || bits_per_pixel <= 0 ||
|
|
bits_per_pixel > 32 || component_count < 0 ||
|
|
component_count > 4 || component_size < 0)
|
|
return false;
|
|
|
|
tile_image.m_eAlphaTrait = component_count == 4 ? BlendPixelTrait : UndefinedPixelTrait;
|
|
if (component_count == 4)
|
|
SetImageAlpha(&tile_image, 255);
|
|
}
|
|
|
|
if ((code != 0x9a) && (code != 0x9b))
|
|
{
|
|
tile_image.m_nColors = 2;
|
|
|
|
if ((bytes_per_line & 0x8000) != 0)
|
|
{
|
|
fseek(m_pFile, 4, SEEK_CUR);
|
|
flag = ReadShortValue();
|
|
tile_image.m_nColors = 1UL * ReadShortValue() + 1;
|
|
}
|
|
|
|
tile_image.m_pColormap = new PixelInfo[tile_image.m_nColors + 1];
|
|
|
|
for (size_t i = 0; i < tile_image.m_nColors; i++)
|
|
{
|
|
tile_image.m_pColormap[i].storage_class = tile_image.m_eStorageClass;
|
|
tile_image.m_pColormap[i].alpha_trait = tile_image.m_eAlphaTrait;
|
|
|
|
double pixel;
|
|
if (tile_image.m_nColors - 1 > 1)
|
|
pixel = ((double) i * (255 / (tile_image.m_nColors - 1)));
|
|
else
|
|
pixel = ((double) i * 255);
|
|
|
|
tile_image.m_pColormap[i].red = pixel;
|
|
tile_image.m_pColormap[i].green = pixel;
|
|
tile_image.m_pColormap[i].blue = pixel;
|
|
tile_image.m_pColormap[i].alpha = 255.0;
|
|
tile_image.m_pColormap[i].alpha_trait = BlendPixelTrait;
|
|
}
|
|
tile_image.m_eStorageClass = PseudoClass;
|
|
|
|
if ((bytes_per_line & 0x8000) != 0)
|
|
{
|
|
for (size_t i = 0; i < tile_image.m_nColors; i++)
|
|
{
|
|
int k = ReadShortValue() % tile_image.m_nColors;
|
|
if ((flag & 0x8000) != 0)
|
|
k = (size_t) i;
|
|
|
|
tile_image.m_pColormap[k].red = static_cast<double>(ReadShortValue());
|
|
tile_image.m_pColormap[k].green = static_cast<double>(ReadShortValue());
|
|
tile_image.m_pColormap[k].blue = static_cast<double>(ReadShortValue());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < tile_image.m_nColors; i++)
|
|
{
|
|
tile_image.m_pColormap[i].red = 255.0 - tile_image.m_pColormap[i].blue;
|
|
tile_image.m_pColormap[i].green = 255.0 - tile_image.m_pColormap[i].green;
|
|
tile_image.m_pColormap[i].blue = 255.0 - tile_image.m_pColormap[i].red;
|
|
}
|
|
}
|
|
}
|
|
if (feof(m_pFile) != 0)
|
|
return false;
|
|
|
|
Aggplus::Rect source;
|
|
if (ReadRectangle(&source) == 0)
|
|
return false;
|
|
|
|
Aggplus::Rect destination;
|
|
if (ReadRectangle(&destination) == 0)
|
|
return false;
|
|
|
|
fseek(m_pFile, 2, SEEK_CUR);
|
|
|
|
if ((code == 0x91) || (code == 0x99) || (code == 0x9b))
|
|
{
|
|
size_t length = ReadShortValue();
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < length - 2; i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
}
|
|
|
|
size_t extent;
|
|
BYTE* pixels;
|
|
if ((code != 0x9a) && (code != 0x9b) && (bytes_per_line & 0x8000) == 0)
|
|
pixels = DecodeImage(tile_image, bytes_per_line, 1, &extent);
|
|
else
|
|
pixels = DecodeImage(tile_image, bytes_per_line, bits_per_pixel, &extent);
|
|
|
|
if (pixels == (unsigned char*) nullptr)
|
|
{
|
|
delete[] pixels;
|
|
return false;
|
|
}
|
|
|
|
BYTE* p = pixels;
|
|
for (size_t y = 0; y < tile_image.m_nHeight; y++)
|
|
{
|
|
if (p > (pixels + extent + m_oImgData.m_nWidth))
|
|
{
|
|
delete[] pixels;
|
|
return 0;
|
|
}
|
|
|
|
unsigned char* q = tile_image.m_pPixelData + 4 * y * frame.Width;
|
|
if (q == (unsigned char *) nullptr)
|
|
break;
|
|
|
|
for (size_t x = 0; x < tile_image.m_nWidth; x++)
|
|
{
|
|
if (tile_image.m_eStorageClass == PseudoClass)
|
|
{
|
|
unsigned char index;
|
|
if (*p < 0 || *p >= tile_image.m_nColors)
|
|
index = 0;
|
|
else
|
|
index = *p;
|
|
|
|
if (tile_image.m_pChannelMap[IndexPixelChannel].traits != UndefinedPixelTrait)
|
|
q[tile_image.m_pChannelMap[IndexPixelChannel].offset] = index;
|
|
|
|
q[tile_image.m_pChannelMap[RedPixelChannel].offset] = tile_image.m_pColormap[index].red;
|
|
q[tile_image.m_pChannelMap[GreenPixelChannel].offset] = tile_image.m_pColormap[index].green;
|
|
q[tile_image.m_pChannelMap[BluePixelChannel].offset] = tile_image.m_pColormap[index].blue;
|
|
}
|
|
else
|
|
{
|
|
if (bits_per_pixel == 16)
|
|
{
|
|
size_t i = (size_t) (*p++);
|
|
int k = (*p);
|
|
|
|
q[tile_image.m_pChannelMap[RedPixelChannel].offset] = (BYTE) ((i & 0x7c) << 1);
|
|
q[tile_image.m_pChannelMap[GreenPixelChannel].offset] = (BYTE) ((i & 0x03) << 6) |((k & 0xe0) >> 2);
|
|
q[tile_image.m_pChannelMap[BluePixelChannel].offset] = (BYTE) ((k & 0x1f) << 3);
|
|
}
|
|
else if (tile_image.m_eAlphaTrait == UndefinedPixelTrait)
|
|
{
|
|
if (p > (pixels + extent + 2 * m_oImgData.m_nWidth))
|
|
{
|
|
delete[] pixels;
|
|
return false;
|
|
}
|
|
|
|
q[tile_image.m_pChannelMap[RedPixelChannel].offset] = *p;
|
|
q[tile_image.m_pChannelMap[GreenPixelChannel].offset] = *(p + tile_image.m_nWidth);
|
|
q[tile_image.m_pChannelMap[BluePixelChannel].offset] = *(p + 2 * tile_image.m_nWidth);
|
|
}
|
|
else
|
|
{
|
|
if (p > (pixels + extent + 3 * m_oImgData.m_nWidth))
|
|
{
|
|
delete[] pixels;
|
|
return false;
|
|
}
|
|
|
|
if (tile_image.m_pChannelMap[AlphaPixelChannel].traits != UndefinedPixelTrait)
|
|
q[tile_image.m_pChannelMap[AlphaPixelChannel].offset] = *p;
|
|
|
|
q[tile_image.m_pChannelMap[RedPixelChannel].offset] = *(p + 1 * tile_image.m_nWidth);
|
|
q[tile_image.m_pChannelMap[GreenPixelChannel].offset] = *(p + 2 * tile_image.m_nWidth);
|
|
q[tile_image.m_pChannelMap[BluePixelChannel].offset] = *(p + 3 * tile_image.m_nWidth);
|
|
}
|
|
}
|
|
p++;
|
|
q += 4;
|
|
}
|
|
if (tile_image.m_eStorageClass == DirectClass && bits_per_pixel != 16)
|
|
{
|
|
p += (component_count - 1) * tile_image.m_nWidth;
|
|
if (p < pixels)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tile_image.m_eStorageClass == PseudoClass ||
|
|
bits_per_pixel == 16 ||
|
|
tile_image.m_eAlphaTrait == UndefinedPixelTrait)
|
|
SetImageAlpha(&tile_image, 255);
|
|
|
|
delete[] pixels;
|
|
if (feof(m_pFile) == 0)
|
|
if ((code == 0x9a) || (code == 0x9b) || ((bytes_per_line & 0x8000) != 0))
|
|
{
|
|
if (m_oImgData.m_nHeight <= tile_image.m_nHeight && m_oImgData.m_nWidth <= tile_image.m_nWidth)
|
|
{
|
|
m_oImgData.Realloc(tile_image.m_nWidth, tile_image.m_nHeight, false);
|
|
memcpy(m_oImgData.m_pPixelData, tile_image.m_pPixelData, m_oImgData.m_nHeight * m_oImgData.m_nWidth * 4);
|
|
}
|
|
else
|
|
CompositeImage(tile_image, destination.X, destination.Y);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (code == 0xc00)
|
|
{
|
|
for (size_t i = 0; i < 24; i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
continue;
|
|
}
|
|
|
|
if (((code >= 0xb0) && (code <= 0xcf)) || ((code >= 0x8000) && (code <= 0x80ff)))
|
|
continue;
|
|
|
|
if ((code == 0xff) || (code == 0xffff))
|
|
continue;
|
|
|
|
if (((code >= 0xd0) && (code <= 0xfe)) || ((code >= 0x8100) && (code <= 0xffff)))
|
|
{
|
|
size_t length = ReadShortValue();
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < length; i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
continue;
|
|
}
|
|
|
|
if ((code >= 0x100) && (code <= 0x7fff))
|
|
{
|
|
size_t length = (size_t) ((code >> 7) & 0xff);
|
|
if (length > GetFileSize())
|
|
return false;
|
|
|
|
for (size_t i = 0; i < length; i++)
|
|
if (fgetc(m_pFile) == EOF)
|
|
break;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!is_pix_data)
|
|
{
|
|
if (!m_oImgData.m_pPixelData)
|
|
m_oImgData.m_pPixelData = (BYTE*)malloc(4 * m_oImgData.m_nHeight * m_oImgData.m_nWidth);
|
|
if (m_oFrame.get_Data())
|
|
memcpy(m_oImgData.m_pPixelData, m_oFrame.get_Data(), 4 * m_oImgData.m_nHeight * m_oImgData.m_nWidth);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t CPictFile::GetFileSize() const
|
|
{
|
|
struct stat st;
|
|
|
|
long long file_discription =
|
|
#ifdef _WIN32
|
|
_fileno(m_pFile);
|
|
#else
|
|
fileno(m_pFile);
|
|
#endif
|
|
if (fstat(file_discription, &st) == 0)
|
|
return st.st_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
size_t CPictFile::Read(const size_t& length, void* data)
|
|
{
|
|
if (!m_pFile)
|
|
return 0;
|
|
if (data == nullptr)
|
|
return 0;
|
|
|
|
unsigned char* q = (unsigned char*) data;
|
|
return fread(q, 1, length, m_pFile);
|
|
}
|
|
|
|
const void* CPictFile::ReadBlobStream(const size_t& length, void* data, size_t* count)
|
|
{
|
|
*count = Read(length, (unsigned char*) data);
|
|
return data;
|
|
}
|
|
|
|
unsigned short CPictFile::ReadShortValue()
|
|
{
|
|
unsigned char buffer[2];
|
|
size_t count;
|
|
*buffer='\0';
|
|
|
|
const unsigned char* p = (const unsigned char*) ReadBlobStream(2, buffer, &count);
|
|
if (count != 2)
|
|
return EOF;
|
|
|
|
unsigned short value = (unsigned short) ((*p++) << 8);
|
|
value |= (unsigned short) (*p++);
|
|
return (unsigned short) (value & 0xffff);
|
|
}
|
|
|
|
signed short CPictFile::ReadSignedShortValue()
|
|
{
|
|
union
|
|
{
|
|
unsigned short unsigned_value;
|
|
signed short signed_value;
|
|
} Quantum;
|
|
|
|
Quantum.unsigned_value = ReadShortValue();
|
|
return (Quantum.signed_value);
|
|
}
|
|
|
|
unsigned int CPictFile::ReadLongValue()
|
|
{
|
|
unsigned char buffer[4];
|
|
*buffer='\0';
|
|
int count = Read(4, buffer);
|
|
|
|
if (count != 4)
|
|
return EOF;
|
|
|
|
const unsigned char* p = (const unsigned char*) buffer;
|
|
|
|
unsigned int value = (unsigned int) (*p++) << 24;
|
|
value |= (unsigned int) (*p++) << 16;
|
|
value |= (unsigned int) (*p++) << 8;
|
|
value |= (unsigned int) (*p++);
|
|
|
|
return value;
|
|
}
|
|
|
|
bool CPictFile::ReadRectangle(Aggplus::Rect* rect)
|
|
{
|
|
rect->Y = (short) ReadShortValue();
|
|
rect->X = (short) ReadShortValue();
|
|
short bottom = (short) ReadShortValue();
|
|
short right = (short) ReadShortValue();
|
|
rect->Height = bottom - rect->Y;
|
|
rect->Width = right - rect->X;
|
|
|
|
if (feof(m_pFile) != 0)
|
|
return false;
|
|
|
|
if (!rect->IsPositive())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void CPictFile::SetImageAlpha(Image* img, const BYTE alpha)
|
|
{
|
|
bool status = true;
|
|
|
|
if (!img->m_pPixelData)
|
|
{
|
|
img->m_pPixelData = (BYTE*)malloc(4 * img->m_nHeight * img->m_nWidth);
|
|
memset(img->m_pPixelData, 255, 4 * img->m_nHeight * img->m_nWidth);
|
|
}
|
|
|
|
img->m_eAlphaTrait = BlendPixelTrait;
|
|
img->m_pChannelMap[AlphaPixelChannel].traits = UpdatePixelTrait;
|
|
for (int y = 0; y < img->m_nHeight; y++)
|
|
{
|
|
if (!status)
|
|
continue;
|
|
|
|
unsigned char* q = img->m_pPixelData + 4 * (y * img->m_nWidth);
|
|
|
|
if (q == nullptr)
|
|
{
|
|
status = false;
|
|
continue;
|
|
}
|
|
for (int x = 0; x < img->m_nWidth; x++)
|
|
{
|
|
int write_mask;
|
|
if (img->m_pChannelMap[WriteMaskPixelChannel].traits == UndefinedPixelTrait)
|
|
write_mask = 255;
|
|
else
|
|
write_mask = q[img->m_pChannelMap[WriteMaskPixelChannel].offset];
|
|
|
|
if (write_mask > (255 / 2))
|
|
if (img->m_pChannelMap[AlphaPixelChannel].traits != UndefinedPixelTrait)
|
|
q[img->m_pChannelMap[AlphaPixelChannel].offset] = alpha;
|
|
|
|
q += 4;
|
|
}
|
|
}
|
|
}
|
|
|
|
BYTE* CPictFile::DecodeImage(const Image& img, size_t bytesPerLine, size_t bitsPerPixel, size_t* extent)
|
|
{
|
|
bool status = true;
|
|
|
|
if (bitsPerPixel <= 8)
|
|
bytesPerLine &= 0x7fff;
|
|
|
|
size_t width = img.m_nWidth;
|
|
size_t bytes_per_pixel = 1;
|
|
|
|
if (bitsPerPixel == 16)
|
|
{
|
|
bytes_per_pixel = 2;
|
|
width *= 2;
|
|
}
|
|
else if (bitsPerPixel == 32)
|
|
width *= img.m_eAlphaTrait ? 4 : 3;
|
|
|
|
if (bytesPerLine == 0)
|
|
bytesPerLine = width;
|
|
|
|
size_t row_bytes = (size_t) (img.m_nWidth | 0x8000);
|
|
|
|
if (img.m_eStorageClass == DirectClass)
|
|
row_bytes = (size_t) ((4 * img.m_nWidth) | 0x8000);
|
|
|
|
BYTE* pixels = new BYTE[img.m_nHeight * row_bytes];
|
|
|
|
if (pixels == nullptr)
|
|
return nullptr;
|
|
|
|
*extent = row_bytes * img.m_nHeight;
|
|
memset(pixels, 0, *extent);
|
|
BYTE* scanline = new BYTE[row_bytes * 2];
|
|
|
|
if (scanline == nullptr)
|
|
{
|
|
delete[] pixels;
|
|
return nullptr;
|
|
}
|
|
|
|
memset(scanline, 0, 2 * row_bytes * sizeof(*scanline));
|
|
|
|
BYTE unpack_buffer[8 * 256];
|
|
memset(unpack_buffer, 0, sizeof(unpack_buffer));
|
|
|
|
if (bytesPerLine < 8)
|
|
{
|
|
for (size_t y = 0; y < img.m_nHeight; y++)
|
|
{
|
|
BYTE* q = pixels + y * (long long) width * 4;
|
|
int count = Read(bytesPerLine, scanline);
|
|
if (count != bytesPerLine)
|
|
{
|
|
status = false;
|
|
break;
|
|
}
|
|
|
|
size_t number_pixels;
|
|
const unsigned char* p = UnpackScanline(scanline, bitsPerPixel, unpack_buffer, &number_pixels);
|
|
if (q + number_pixels > pixels + (*extent))
|
|
{
|
|
status = false;
|
|
break;
|
|
}
|
|
memcpy(q, p, (size_t) number_pixels);
|
|
}
|
|
delete[] scanline;
|
|
if (!status)
|
|
delete[] pixels;
|
|
return pixels;
|
|
}
|
|
|
|
for (size_t y = 0; y < img.m_nHeight; y++)
|
|
{
|
|
BYTE* q = pixels + y * width;
|
|
|
|
size_t scanline_length;
|
|
if (bytesPerLine > 250)
|
|
scanline_length = ReadShortValue();
|
|
else
|
|
scanline_length = fgetc(m_pFile);
|
|
|
|
if ((scanline_length >= row_bytes) || (scanline_length == 0))
|
|
{
|
|
status = false;
|
|
break;
|
|
}
|
|
|
|
int count = Read(scanline_length,scanline);
|
|
if (count != scanline_length)
|
|
{
|
|
status = false;
|
|
break;
|
|
}
|
|
|
|
for (size_t j = 0; j < scanline_length; )
|
|
if ((scanline[j] & 0x80) == 0)
|
|
{
|
|
size_t length = (size_t) ((scanline[j] & 0xff) + 1);
|
|
size_t number_pixels = length * bytes_per_pixel;
|
|
const unsigned char* p = UnpackScanline(scanline + j + 1, bitsPerPixel, unpack_buffer, &number_pixels);
|
|
if ((q - pixels + number_pixels) <= *extent)
|
|
memcpy(q, p, number_pixels);
|
|
q += number_pixels;
|
|
j += length * bytes_per_pixel + 1;
|
|
}
|
|
else
|
|
{
|
|
size_t length = ((scanline[j] ^ 0xff) & 0xff) + 2;
|
|
size_t number_pixels = bytes_per_pixel;
|
|
const unsigned char* p = UnpackScanline(scanline + j + 1, bitsPerPixel, unpack_buffer, &number_pixels);
|
|
for (size_t i = 0; i < length; i++)
|
|
{
|
|
if ((q - pixels + number_pixels) <= *extent)
|
|
memcpy(q, p, (size_t) number_pixels);
|
|
q += number_pixels;
|
|
}
|
|
j += bytes_per_pixel + 1;
|
|
}
|
|
}
|
|
delete[] scanline;
|
|
|
|
if (!status)
|
|
{
|
|
delete[] pixels;
|
|
pixels = nullptr;
|
|
}
|
|
|
|
return pixels;
|
|
}
|
|
|
|
const BYTE* CPictFile::UnpackScanline(const BYTE* pixels, const size_t& bitsPerPixel, BYTE* scanline, size_t* bytesPerLine)
|
|
{
|
|
const unsigned char* p = pixels;
|
|
unsigned char* q = scanline;
|
|
switch (bitsPerPixel)
|
|
{
|
|
case 8:
|
|
case 16:
|
|
case 32:
|
|
return pixels;
|
|
case 4:
|
|
{
|
|
for (long long i = 0; i < (long long) *bytesPerLine; i++)
|
|
{
|
|
*q++ = (*p >> 4) & 0xff;
|
|
*q++ = (*p & 15);
|
|
p++;
|
|
}
|
|
*bytesPerLine *= 2;
|
|
break;
|
|
}
|
|
case 2:
|
|
{
|
|
for (long long i = 0; i < (long long) *bytesPerLine; i++)
|
|
{
|
|
*q++ = (*p >> 6) & 0x03;
|
|
*q++ = (*p >> 4) & 0x03;
|
|
*q++ = (*p >> 2) & 0x03;
|
|
*q++ = (*p & 3);
|
|
p++;
|
|
}
|
|
*bytesPerLine *= 4;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
for (long long i = 0; i < (long long) *bytesPerLine; i++)
|
|
{
|
|
*q++ = (*p >> 7) & 0x01;
|
|
*q++ = (*p >> 6) & 0x01;
|
|
*q++ = (*p >> 5) & 0x01;
|
|
*q++ = (*p >> 4) & 0x01;
|
|
*q++ = (*p >> 3) & 0x01;
|
|
*q++ = (*p >> 2) & 0x01;
|
|
*q++ = (*p >> 1) & 0x01;
|
|
*q++ = (*p & 0x01);
|
|
p++;
|
|
}
|
|
*bytesPerLine *= 8;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return scanline;
|
|
}
|
|
|
|
void CPictFile::ReadPolygon()
|
|
{
|
|
size_t size = ReadShortValue();
|
|
fseek(m_pFile, 8, SEEK_CUR);
|
|
|
|
size = (size - 10) / 4;
|
|
const size_t max_possible_points = GetFileSize() - ftell(m_pFile);
|
|
if (size > max_possible_points)
|
|
size = max_possible_points;
|
|
|
|
m_arLastPolygon.resize(size);
|
|
|
|
for (size_t i = 0; i < size; i++)
|
|
{
|
|
int y = ReadShortValue();
|
|
int x = ReadShortValue();
|
|
m_arLastPolygon[i] = Aggplus::Point(x, y);
|
|
if (feof(m_pFile))
|
|
{
|
|
m_arLastPolygon.resize(i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Aggplus::Rect CPictFile::ContractRect(const Aggplus::Rect& rect, bool isFrame)
|
|
{
|
|
if (!isFrame)
|
|
return rect;
|
|
|
|
int pen_size = (m_nPenWidth + m_nPenHeight) / 2;
|
|
|
|
if (pen_size * 2 > rect.Width)
|
|
pen_size = (rect.Width + 1) / 2;
|
|
if (pen_size * 2 > rect.Height)
|
|
pen_size = (rect.Height + 1) / 2;
|
|
|
|
const long X[2] = {rect.GetLeft() + pen_size / 2, rect.GetRight() - (pen_size + 1) / 2};
|
|
const long Y[2] = {rect.GetTop() + pen_size / 2, rect.GetBottom() - (pen_size + 1) / 2};
|
|
|
|
return Aggplus::Rect(X[0], Y[0], X[1] - X[0], Y[1] - Y[0]);
|
|
}
|
|
|
|
void CPictFile::DrawPolygon(bool isFrame)
|
|
{
|
|
InitializeRenderer();
|
|
|
|
size_t pen_size = (m_nPenWidth + m_nPenHeight) / 2;
|
|
long deca1TL[2] = {0, 0}, deca1BR[2] = {static_cast<long>(m_nPenWidth), static_cast<long>(m_nPenWidth)};
|
|
|
|
if (isFrame)
|
|
{
|
|
deca1TL[0] += pen_size / 2;
|
|
deca1TL[1] += pen_size / 2;
|
|
deca1BR[0] -= (pen_size + 1) / 2;
|
|
deca1BR[1] -= (pen_size + 1) / 2;
|
|
}
|
|
else
|
|
deca1BR[0] = deca1BR[1] = 0;
|
|
|
|
size_t points_count = m_arLastPolygon.size();
|
|
if (points_count < 1)
|
|
return;
|
|
|
|
double bary[2] = {0.0, 0.0};
|
|
for (int i = 0; i < points_count; i++)
|
|
{
|
|
const Aggplus::Point& pt = m_arLastPolygon[i];
|
|
bary[0] += double(pt.X);
|
|
bary[1] += double(pt.Y);
|
|
}
|
|
bary[0] /= double(points_count);
|
|
bary[1] /= double(points_count);
|
|
|
|
|
|
std::vector<Aggplus::PointF> B2Dpoly;
|
|
B2Dpoly.resize(points_count);
|
|
for (int i = 0; i < points_count; i++)
|
|
{
|
|
const Aggplus::Point& pt = m_arLastPolygon[i];
|
|
double x = (double(pt.X) < bary[0]) ? pt.X + deca1TL[0] : pt.X + deca1BR[0];
|
|
double y = (double(pt.Y) < bary[1]) ? pt.Y + deca1TL[1] : pt.Y + deca1BR[1];
|
|
B2Dpoly[i] = Aggplus::PointF(x, y);
|
|
}
|
|
|
|
m_pRenderer->PathCommandStart();
|
|
m_pRenderer->BeginCommand(c_nPathType);
|
|
m_pRenderer->PathCommandMoveTo(B2Dpoly[0].X, B2Dpoly[0].Y);
|
|
|
|
for (int i = 1; i < points_count; i++)
|
|
m_pRenderer->PathCommandLineTo(B2Dpoly[i].X, B2Dpoly[i].Y);
|
|
|
|
|
|
if (!isFrame)
|
|
m_pRenderer->Fill();
|
|
|
|
m_pRenderer->DrawPath(c_nStroke);
|
|
m_pRenderer->EndCommand(c_nPathType);
|
|
m_pRenderer->PathCommandEnd();
|
|
}
|
|
|
|
void CPictFile::DrawLine(const Aggplus::Point& p1, const Aggplus::Point& p2)
|
|
{
|
|
long dir[2] = {p2.X - p1.X, p2.Y - p1.Y};
|
|
long X[2] = {p1.X, p2.X};
|
|
long Y[2] = {p1.Y, p2.Y};
|
|
|
|
if (dir[0] == 0)
|
|
{
|
|
if (X[0] < X[1])
|
|
X[1] += m_nPenWidth;
|
|
else
|
|
X[0] += m_nPenWidth;
|
|
Y[1] += m_nPenHeight;
|
|
|
|
std::vector<Aggplus::Point> poly;
|
|
poly.resize(5);
|
|
poly[0] = Aggplus::Point(X[0], Y[0]);
|
|
poly[1] = Aggplus::Point(X[1], Y[0]);
|
|
poly[2] = Aggplus::Point(X[1], Y[1]);
|
|
poly[3] = Aggplus::Point(X[0], Y[1]);
|
|
poly[4] = Aggplus::Point(X[0], Y[0]);
|
|
std::vector<Aggplus::Point> tmp = m_arLastPolygon;
|
|
m_arLastPolygon = poly;
|
|
DrawPolygon(false);
|
|
m_arLastPolygon = tmp;
|
|
}
|
|
else if (dir[1] == 0)
|
|
{
|
|
if (Y[0] < Y[1])
|
|
Y[1] += m_nPenHeight;
|
|
else
|
|
Y[0] += m_nPenHeight;
|
|
X[1] += m_nPenWidth;
|
|
|
|
std::vector<Aggplus::Point> poly;
|
|
poly.resize(5);
|
|
poly[0] = Aggplus::Point(X[0], Y[0]);
|
|
poly[1] = Aggplus::Point(X[1], Y[0]);
|
|
poly[2] = Aggplus::Point(X[1], Y[1]);
|
|
poly[3] = Aggplus::Point(X[0], Y[1]);
|
|
poly[4] = Aggplus::Point(X[0], Y[0]);
|
|
std::vector<Aggplus::Point> tmp = m_arLastPolygon;
|
|
m_arLastPolygon = poly;
|
|
DrawPolygon(false);
|
|
m_arLastPolygon = tmp;
|
|
}
|
|
else if (dir[0] * dir[0] + dir[1] * dir[1] < 25)
|
|
{
|
|
long orig_pt[4][2] = {{p1.X, p1.Y},
|
|
{p1.X + static_cast<long>(m_nPenWidth), p1.Y},
|
|
{p1.X + static_cast<long>(m_nPenWidth), p1.Y + static_cast<long>(m_nPenHeight)},
|
|
{p1.X, p1.Y + static_cast<long>(m_nPenHeight)}};
|
|
int orig_avoid = dir[0] > 0 ? (dir[1] > 0 ? 2 : 1) : (dir[1] > 0 ? 3 : 0);
|
|
long dest_pt[4][2] = {{p2.X, p2.Y},
|
|
{p2.X + static_cast<long>(m_nPenWidth), p2.Y},
|
|
{p2.X + static_cast<long>(m_nPenWidth), p2.Y + static_cast<long>(m_nPenHeight)},
|
|
{p2.X, p2.Y + static_cast<long>(m_nPenHeight)}};
|
|
std::vector<Aggplus::Point> poly;
|
|
poly.resize(7);
|
|
for (int w = 1; w < 4; w++)
|
|
{
|
|
int wh = (w + orig_avoid) % 4;
|
|
poly[w - 1] = Aggplus::Point(orig_pt[wh][0], orig_pt[wh][1]);
|
|
}
|
|
|
|
for (int w = 3; w < 6; w++)
|
|
{
|
|
int wh = (w + orig_avoid) % 4;
|
|
poly[w] = Aggplus::Point(dest_pt[wh][0], dest_pt[wh][1]);
|
|
}
|
|
|
|
int wh = (orig_avoid + 1) % 4;
|
|
poly[6] = Aggplus::Point(orig_pt[wh][0], orig_pt[wh][1]);
|
|
std::vector<Aggplus::Point> tmp = m_arLastPolygon;
|
|
m_arLastPolygon = poly;
|
|
DrawPolygon(false);
|
|
m_arLastPolygon = tmp;
|
|
}
|
|
else
|
|
{
|
|
long decal[2] = {static_cast<long>(m_nPenWidth / 2), static_cast<long>(m_nPenHeight / 2)};
|
|
std::vector<Aggplus::Point> poly;
|
|
poly.resize(2);
|
|
poly[0] = Aggplus::Point(p1.X + decal[0], p1.Y + decal[1]);
|
|
poly[1] = Aggplus::Point(p2.X + decal[0], p2.Y + decal[1]);
|
|
std::vector<Aggplus::Point> tmp = m_arLastPolygon;
|
|
m_arLastPolygon = poly;
|
|
DrawPolygon(false);
|
|
m_arLastPolygon = tmp;
|
|
}
|
|
}
|
|
|
|
void CPictFile::DrawRect(bool isFrame)
|
|
{
|
|
InitializeRenderer();
|
|
|
|
Aggplus::Rect new_rect = ContractRect(m_oLastRect, isFrame);
|
|
const long X[2] = {new_rect.GetLeft(), new_rect.GetRight()};
|
|
const long Y[2] = {new_rect.GetTop(), new_rect.GetBottom()};
|
|
|
|
m_pRenderer->PathCommandStart();
|
|
m_pRenderer->BeginCommand(c_nPathType);
|
|
Aggplus::CGraphicsPath path;
|
|
path.AddRectangle(X[0], Y[0], X[1] - X[0], Y[1] - Y[0]);
|
|
size_t points_count = path.GetPointCount();
|
|
|
|
Aggplus::PointF* points = new Aggplus::PointF[points_count];
|
|
path.GetPathPoints(points, points_count);
|
|
|
|
m_pRenderer->PathCommandMoveTo(points[0].X, points[0].Y);
|
|
|
|
for (size_t i = 1; i < points_count; i++)
|
|
m_pRenderer->PathCommandLineTo(points[i].X, points[i].Y);
|
|
|
|
if (!isFrame)
|
|
m_pRenderer->Fill();
|
|
|
|
m_pRenderer->DrawPath(c_nStroke);
|
|
m_pRenderer->EndCommand(c_nPathType);
|
|
m_pRenderer->PathCommandEnd();
|
|
|
|
delete[] points;
|
|
}
|
|
|
|
void CPictFile::DrawRoundRect(bool isFrame)
|
|
{
|
|
InitializeRenderer();
|
|
|
|
Aggplus::Rect oval = ContractRect(m_oLastRoundRect, isFrame);
|
|
int ovalW = m_nPenWidth;
|
|
int ovalH = m_nPenHeight;
|
|
const long X[2] = {oval.GetLeft(), oval.GetRight()};
|
|
const long Y[2] = {oval.GetTop(), oval.GetBottom()};
|
|
long width = X[1] - X[0];
|
|
long height = Y[1] - Y[0];
|
|
|
|
if (ovalW > width)
|
|
ovalW = static_cast<int>(width);
|
|
if (ovalH > height)
|
|
ovalH = static_cast<int>(height);
|
|
|
|
m_pRenderer->PathCommandStart();
|
|
m_pRenderer->BeginCommand(c_nPathType);
|
|
Aggplus::CGraphicsPath path;
|
|
path.AddRoundRectangle(X[0], Y[0], X[1] - X[0], Y[1] - Y[0], width == 0.0 ? 0.0 : ovalW / width, height == 0.0 ? 0.0 : ovalH / height);
|
|
size_t points_count = path.GetPointCount();
|
|
|
|
Aggplus::PointF* points = new Aggplus::PointF[points_count];
|
|
path.GetPathPoints(points, points_count);
|
|
|
|
m_pRenderer->PathCommandMoveTo(points[0].X, points[0].Y);
|
|
|
|
for (size_t i = 1; i < points_count; i++)
|
|
{
|
|
if (path.IsCurvePoint(i))
|
|
{
|
|
m_pRenderer->PathCommandCurveTo(points[i].X, points[i].Y,
|
|
points[i + 1].X, points[i + 1].Y,
|
|
points[i + 2].X, points[i + 2].Y);
|
|
i += 2;
|
|
}
|
|
m_pRenderer->PathCommandLineTo(points[i].X, points[i].Y);
|
|
}
|
|
|
|
|
|
if (!isFrame)
|
|
m_pRenderer->Fill();
|
|
|
|
m_pRenderer->DrawPath(c_nStroke);
|
|
m_pRenderer->EndCommand(c_nPathType);
|
|
m_pRenderer->PathCommandEnd();
|
|
|
|
delete[] points;
|
|
}
|
|
|
|
void CPictFile::DrawOval(bool isFrame)
|
|
{
|
|
InitializeRenderer();
|
|
|
|
Aggplus::Rect rect = ContractRect(m_oLastOval, isFrame);
|
|
const long X[2] = {rect.GetLeft(), rect.GetRight()};
|
|
const long Y[2] = {rect.GetTop(), rect.GetBottom()};
|
|
|
|
m_pRenderer->PathCommandStart();
|
|
m_pRenderer->BeginCommand(c_nPathType);
|
|
Aggplus::CGraphicsPath path;
|
|
path.AddEllipse(X[0], Y[0], X[1] - X[0], Y[1] - Y[0]);
|
|
size_t points_count = path.GetPointCount();
|
|
|
|
Aggplus::PointF* points = new Aggplus::PointF[points_count];
|
|
path.GetPathPoints(points, points_count);
|
|
|
|
m_pRenderer->PathCommandMoveTo(points[0].X, points[0].Y);
|
|
|
|
for (size_t i = 1; i < points_count; i += 3)
|
|
m_pRenderer->PathCommandCurveTo(points[i].X, points[i].Y,
|
|
points[i + 1].X, points[i + 1].Y,
|
|
points[i + 2].X, points[i + 2].Y);
|
|
|
|
if (!isFrame)
|
|
m_pRenderer->Fill();
|
|
|
|
m_pRenderer->DrawPath(c_nStroke);
|
|
m_pRenderer->EndCommand(c_nPathType);
|
|
m_pRenderer->PathCommandEnd();
|
|
|
|
delete[] points;
|
|
}
|
|
|
|
void CPictFile::DrawArc()
|
|
{
|
|
InitializeRenderer();
|
|
|
|
short start_angle = ReadShortValue();
|
|
short angle = ReadShortValue();
|
|
if (feof(m_pFile) || (m_nPenWidth == 0 && m_nPenHeight == 0))
|
|
return;
|
|
|
|
if (angle < 0)
|
|
{
|
|
start_angle = start_angle + angle;
|
|
angle = -angle;
|
|
}
|
|
|
|
double ang1 = agg::deg2rad(start_angle);
|
|
double ang2 = agg::deg2rad(angle);
|
|
|
|
m_pRenderer->PathCommandStart();
|
|
m_pRenderer->BeginCommand(c_nPathType);
|
|
Aggplus::CGraphicsPath path;
|
|
path.AddArc(m_oLastArc.GetLeft(), m_oLastArc.GetTop(), m_oLastArc.Width, m_oLastArc.Height, ang1, ang2);
|
|
|
|
size_t points_count = path.GetPointCount();
|
|
|
|
Aggplus::PointF* points = new Aggplus::PointF[points_count];
|
|
path.GetPathPoints(points, points_count);
|
|
|
|
m_pRenderer->PathCommandMoveTo(points[0].X, points[0].Y);
|
|
|
|
for (size_t i = 1; i < points_count; i += 3)
|
|
m_pRenderer->PathCommandCurveTo(points[i].X, points[i].Y,
|
|
points[i + 1].X, points[i + 1].Y,
|
|
points[i + 2].X, points[i + 2].Y);
|
|
|
|
m_pRenderer->DrawPath(c_nStroke);
|
|
m_pRenderer->EndCommand(c_nPathType);
|
|
m_pRenderer->PathCommandEnd();
|
|
|
|
delete[] points;
|
|
}
|
|
|
|
void CPictFile::ReadAndDrawText(int x, int y)
|
|
{
|
|
InitializeRenderer();
|
|
|
|
char text[256];
|
|
char byte_len = fgetc(m_pFile);
|
|
unsigned long len = static_cast<unsigned long>(byte_len) & 0x000000ff;
|
|
len = Read(len, &text);
|
|
|
|
if (m_nPenWidth == 0 && m_nPenHeight == 0)
|
|
return;
|
|
|
|
while (len > 0 && static_cast<unsigned char>(text[len - 1]) < 32)
|
|
len--;
|
|
text[len] = 0;
|
|
m_pRenderer->put_FontName(m_wsFontName);
|
|
m_pRenderer->put_FontSize(m_nFontSize);
|
|
m_pRenderer->put_FontStyle(m_nFontStyle);
|
|
|
|
std::wstring ws_text(len, L'\0');
|
|
std::mbstowcs(&ws_text[0], text, len);
|
|
|
|
m_pRenderer->BeginCommand(c_nTextGraphicType);
|
|
m_pRenderer->CommandDrawText(ws_text, x, y, 0.0, 0.0);
|
|
m_pRenderer->EndCommand(c_nTextGraphicType);
|
|
}
|
|
|
|
void CPictFile::InitializeRenderer()
|
|
{
|
|
if (m_pFrameData)
|
|
return;
|
|
|
|
m_pFrameData = new BYTE[4 * m_oImgData.m_nWidth * m_oImgData.m_nHeight];
|
|
m_oFrame.put_Data(m_pFrameData);
|
|
m_oFrame.put_Width(m_oImgData.m_nWidth);
|
|
m_oFrame.put_Height(m_oImgData.m_nHeight);
|
|
m_oFrame.put_Stride(4 * m_oImgData.m_nWidth);
|
|
|
|
m_pRenderer->CreateFromBgraFrame(&m_oFrame);
|
|
m_pRenderer->put_Width(m_oImgData.m_nWidth);
|
|
m_pRenderer->put_Height(m_oImgData.m_nHeight);
|
|
m_pRenderer->SetSwapRGB(false);
|
|
m_pRenderer->put_PenColor(0x000000);
|
|
}
|
|
|
|
|
|
BYTE* CPictFile::GetPixels(const Image& image, const long long& x, const long long& y, const size_t& width, const size_t& height) const
|
|
{
|
|
BYTE* pixels = image.m_pPixelData + 4 * (y * image.m_nWidth + x);
|
|
|
|
if (!pixels)
|
|
return nullptr;
|
|
|
|
if (image.m_nWidth == 0)
|
|
return nullptr;
|
|
|
|
long long offset = y * image.m_nWidth;
|
|
|
|
offset += x;
|
|
size_t length = 4 * width * sizeof(unsigned char);
|
|
|
|
size_t rows = height;
|
|
size_t extent = length * rows;
|
|
|
|
BYTE* q = pixels;
|
|
|
|
if (image.m_nWidth == width)
|
|
{
|
|
length = extent;
|
|
rows = 1UL;
|
|
}
|
|
|
|
BYTE* p = image.m_pPixelData + 4 * offset;
|
|
for (size_t i = 0; i < rows; i++)
|
|
{
|
|
memcpy(q, p, length);
|
|
p += 4 * image.m_nWidth;
|
|
q += 4 * width;
|
|
}
|
|
|
|
return pixels;
|
|
}
|
|
|
|
void CPictFile::CompositeImage(const Image& composite,const long long& xOffset, const long long& yOffset)
|
|
{
|
|
m_oImgData.m_eStorageClass = DirectClass;
|
|
Image source_image(composite);
|
|
source_image.m_pPixelData = (BYTE*)malloc(source_image.m_nWidth * source_image.m_nHeight * 4);
|
|
memcpy(source_image.m_pPixelData, composite.m_pPixelData, source_image.m_nWidth * source_image.m_nHeight * 4);
|
|
|
|
m_oImgData.m_pChannelMap[RedPixelChannel].traits = UpdatePixelTrait;
|
|
m_oImgData.m_pChannelMap[GreenPixelChannel].traits = UpdatePixelTrait;
|
|
m_oImgData.m_pChannelMap[BluePixelChannel].traits = UpdatePixelTrait;
|
|
m_oImgData.m_pChannelMap[AlphaPixelChannel].traits = UpdatePixelTrait;
|
|
|
|
source_image.m_pChannelMap[RedPixelChannel].traits = CopyPixelTrait;
|
|
source_image.m_pChannelMap[GreenPixelChannel].traits = CopyPixelTrait;
|
|
source_image.m_pChannelMap[BluePixelChannel].traits = CopyPixelTrait;
|
|
source_image.m_pChannelMap[AlphaPixelChannel].traits = CopyPixelTrait;
|
|
|
|
bool status = false;
|
|
if (!((xOffset < 0) || (yOffset < 0)) && !((xOffset + source_image.m_nWidth) > m_oImgData.m_nWidth) && !((yOffset + source_image.m_nHeight) > m_oImgData.m_nHeight))
|
|
{
|
|
if ((source_image.m_eAlphaTrait == UndefinedPixelTrait) &&
|
|
(m_oImgData.m_eAlphaTrait != UndefinedPixelTrait))
|
|
SetImageAlpha(&source_image, 255);
|
|
|
|
status = true;
|
|
for (size_t y = 0; y < source_image.m_nHeight; y++)
|
|
{
|
|
if (!status)
|
|
continue;
|
|
|
|
const BYTE* p = GetPixels(source_image,0,y,source_image.m_nWidth, 1);
|
|
BYTE* q = GetPixels(m_oImgData, xOffset, y + yOffset, source_image.m_nWidth, 1);
|
|
|
|
if (p == nullptr || q == nullptr)
|
|
{
|
|
status = false;
|
|
continue;
|
|
}
|
|
|
|
for (size_t x = 0; x < source_image.m_nWidth; x++)
|
|
{
|
|
BYTE read_mask;
|
|
if (source_image.m_pChannelMap[ReadMaskPixelChannel].traits == UndefinedPixelTrait)
|
|
read_mask = 255;
|
|
else
|
|
read_mask = p[source_image.m_pChannelMap[ReadMaskPixelChannel].offset];
|
|
|
|
if (read_mask <= (255.0 / 2.0))
|
|
{
|
|
p += 4;
|
|
q += 4;
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
PixelChannel channel = source_image.m_pChannelMap[i].channel;
|
|
PixelTrait source_traits = source_image.m_pChannelMap[channel].traits;
|
|
PixelTrait traits = m_oImgData.m_pChannelMap[channel].traits;
|
|
|
|
if ((source_traits == UndefinedPixelTrait) || (traits == UndefinedPixelTrait))
|
|
continue;
|
|
q[m_oImgData.m_pChannelMap[channel].offset] = p[i];
|
|
}
|
|
p += 4;
|
|
q += 4;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
status = true;
|
|
for (size_t y = 0; y < m_oImgData.m_nHeight; y++)
|
|
{
|
|
if (!status)
|
|
continue;
|
|
|
|
if (y < yOffset)
|
|
continue;
|
|
if (y - yOffset >= source_image.m_nHeight)
|
|
continue;
|
|
|
|
const BYTE* pixels = nullptr;
|
|
const BYTE* p = nullptr;
|
|
if (y >= yOffset && y - yOffset < source_image.m_nHeight)
|
|
{
|
|
p = GetPixels(source_image, 0, y - yOffset, source_image.m_nWidth,1);
|
|
if (!p)
|
|
{
|
|
status = false;
|
|
continue;
|
|
}
|
|
pixels = p;
|
|
if (xOffset < 0)
|
|
p -= xOffset * 4;
|
|
}
|
|
|
|
BYTE* q = GetPixels(m_oImgData, 0, y, m_oImgData.m_nWidth,1);
|
|
if (!q)
|
|
{
|
|
status = false;
|
|
continue;
|
|
}
|
|
|
|
for (size_t x = 0; x < m_oImgData.m_nWidth; x++)
|
|
{
|
|
double
|
|
Dc = 0.0,
|
|
Sa = 0.0,
|
|
Sc = 0.0;
|
|
|
|
if (x < xOffset)
|
|
{
|
|
q += 4;
|
|
continue;
|
|
}
|
|
if (x - xOffset >= source_image.m_nWidth)
|
|
break;
|
|
|
|
if (!pixels || x < xOffset || x - xOffset >= source_image.m_nWidth)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
PixelChannel channel = m_oImgData.m_pChannelMap[i].channel;
|
|
PixelTrait traits = m_oImgData.m_pChannelMap[channel].traits;
|
|
PixelTrait source_traits = source_image.m_pChannelMap[channel].traits;
|
|
if (traits == UndefinedPixelTrait || source_traits == UndefinedPixelTrait)
|
|
continue;
|
|
|
|
q[i] = 0;
|
|
}
|
|
q += 4;
|
|
continue;
|
|
}
|
|
|
|
BYTE pixel_alpha = 0;
|
|
if (source_image.m_pChannelMap[AlphaPixelChannel].traits != UndefinedPixelTrait)
|
|
pixel_alpha = p[source_image.m_pChannelMap[AlphaPixelChannel].offset];
|
|
Sa = (1.0 / 255.0) * pixel_alpha;
|
|
Sa = Sa == 0 ? 1 : Sa;
|
|
pixel_alpha = 0;
|
|
if (m_oImgData.m_pChannelMap[AlphaPixelChannel].traits != UndefinedPixelTrait)
|
|
pixel_alpha = q[m_oImgData.m_pChannelMap[AlphaPixelChannel].offset];
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
double pixel = 0.0;
|
|
PixelChannel channel = m_oImgData.m_pChannelMap[i].channel;
|
|
PixelTrait traits = m_oImgData.m_pChannelMap[channel].traits;
|
|
PixelTrait source_traits = source_image.m_pChannelMap[channel].traits;
|
|
if (traits == UndefinedPixelTrait)
|
|
continue;
|
|
if ((channel == AlphaPixelChannel) &&
|
|
((traits & UpdatePixelTrait) != 0))
|
|
{
|
|
pixel = 255.0 * Sa;
|
|
q[i] = pixel > 255 ? 255 : pixel < 0 ? 0 : pixel;
|
|
continue;
|
|
}
|
|
if (source_traits == UndefinedPixelTrait)
|
|
continue;
|
|
|
|
Sc = p[source_image.m_pChannelMap[channel].offset];
|
|
Dc=q[i];
|
|
|
|
if ((traits & CopyPixelTrait) != 0)
|
|
{
|
|
q[i] = Dc > 255 ? 255 : Dc < 0 ? 0 : Dc;
|
|
continue;
|
|
}
|
|
|
|
pixel = 255.0 * (1.0 / 255.0) * Sa * Sc;
|
|
q[i] = pixel > 255 ? 255 : pixel < 0 ? 0 : pixel;
|
|
}
|
|
|
|
p += 4;
|
|
if (p >= (pixels + 4 * source_image.m_nWidth))
|
|
p = pixels;
|
|
q += 4;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|