Compare commits

...

7 Commits

Author SHA1 Message Date
e11ad7173c Fix link 2025-12-25 21:28:40 +03:00
8984379cdb Add prefix for ios_simulator 2025-10-31 20:22:47 +03:00
15924aa808 Fix linux build 2025-10-27 22:59:21 +03:00
62276b1e6e Add lib for windows 2025-10-14 01:28:39 +03:00
02c848fa54 Fix memory leak 2025-10-13 19:13:57 +03:00
6883308e42 Add WebP encode 2025-10-13 19:07:09 +03:00
5fd743f603 Add WebP decode 2025-10-13 17:29:55 +03:00
10 changed files with 402 additions and 1 deletions

2
Common/3dParty/webp/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
build
libwebp

View File

@ -0,0 +1,26 @@
WEBP_BUILDS_PLATFORM_PREFIX = $$CORE_BUILDS_PLATFORM_PREFIX
core_ios : xcframework_platform_ios_simulator {
WEBP_BUILDS_PLATFORM_PREFIX = ios_simulator
}
WEBP_BUILD_PATH = $$PWD/build/$$WEBP_BUILDS_PLATFORM_PREFIX
core_windows {
core_win_32 {
BUILD_PLATFORM = x86
} else {
BUILD_PLATFORM = x64
}
core_debug {
LIBS += -L$$WEBP_BUILD_PATH/debug-static/$$BUILD_PLATFORM/lib -llibwebp_debug
} else {
LIBS += -L$$WEBP_BUILD_PATH/release-static/$$BUILD_PLATFORM/lib -llibwebp
}
}
core_linux | core_android | core_mac | core_ios {
LIBS += \
-L$$WEBP_BUILD_PATH/$$CORE_BUILDS_CONFIGURATION_PREFIX/src/.libs -lwebp \
-L$$WEBP_BUILD_PATH/$$CORE_BUILDS_CONFIGURATION_PREFIX/sharpyuv/.libs -lsharpyuv
}

View File

@ -51,10 +51,16 @@
#else
#define CXIMAGE_SUPPORT_HEIF 0
#endif
#ifdef SUPPORT_LIB_WEBP_SOURCES
#define CXIMAGE_SUPPORT_WEBP 1
#else
#define CXIMAGE_SUPPORT_WEBP 0
#endif
#define CXIMAGE_SUPPORT_RAW 1
#else
#define CXIMAGE_SUPPORT_HEIF 0
#define CXIMAGE_SUPPORT_RAW 0
#define CXIMAGE_SUPPORT_WEBP 0
#endif
#ifdef CXIMAGE_DISABLE_SUPPORT_MNG

View File

@ -136,6 +136,9 @@ CXIMAGE_FORMAR_PIC = 25,
#if CXIMAGE_SUPPORT_HEIF
CXIMAGE_FORMAT_HEIF = 26,
#endif
#if CXIMAGE_SUPPORT_WEBP
CXIMAGE_FORMAT_WEBP = 27,
#endif
CMAX_IMAGE_FORMATS = CXIMAGE_SUPPORT_BMP + CXIMAGE_SUPPORT_GIF + CXIMAGE_SUPPORT_JPG +
CXIMAGE_SUPPORT_PNG + CXIMAGE_SUPPORT_MNG + CXIMAGE_SUPPORT_ICO +
CXIMAGE_SUPPORT_TIF + CXIMAGE_SUPPORT_TGA + CXIMAGE_SUPPORT_PCX +
@ -143,7 +146,7 @@ CMAX_IMAGE_FORMATS = CXIMAGE_SUPPORT_BMP + CXIMAGE_SUPPORT_GIF + CXIMAGE_SUPPORT
CXIMAGE_SUPPORT_JBG + CXIMAGE_SUPPORT_JP2 + CXIMAGE_SUPPORT_JPC +
CXIMAGE_SUPPORT_PGX + CXIMAGE_SUPPORT_PNM + CXIMAGE_SUPPORT_RAS +
CXIMAGE_SUPPORT_SKA + CXIMAGE_SUPPORT_RAW + CXIMAGE_SUPPORT_PSD +
CXIMAGE_SUPPORT_HEIF + 1
CXIMAGE_SUPPORT_HEIF + CXIMAGE_SUPPORT_WEBP + 1
};
#if CXIMAGE_SUPPORT_EXIF

View File

@ -286,6 +286,7 @@ SOURCES += \
!build_xp {
CONFIG += support_heif
CONFIG += support_webp
}
support_heif {
@ -294,6 +295,12 @@ support_heif {
SOURCES += $$LIB_GRAPHICS_PRI_PATH/raster/heif/heif.cpp
}
support_webp {
DEFINES += SUPPORT_LIB_WEBP_SOURCES
include($$CORE_ROOT_DIR/Common/3dParty/webp/webp.pri)
SOURCES += $$LIB_GRAPHICS_PRI_PATH/raster/WebP/webp.cpp
}
SOURCES += \
$$LIB_GRAPHICS_PRI_PATH/cximage/jasper/base/jas_cm.c \
$$LIB_GRAPHICS_PRI_PATH/cximage/jasper/base/jas_debug.c \

View File

@ -48,6 +48,10 @@
#include "heif/heif.h"
#endif
#if CXIMAGE_SUPPORT_WEBP
#include "WebP/webp.h"
#endif
#include <cmath>
#define BGRA_FRAME_CXIMAGE_MAX_MEMORY 67108864 // 256Mb (*4 channel)
@ -462,6 +466,13 @@ bool CBgraFrame::OpenFile(const std::wstring& strFileName, unsigned int nFileTyp
}
#endif
#if CXIMAGE_SUPPORT_WEBP
if (CXIMAGE_FORMAT_WEBP == m_nFileType)
{
return NSWebP::CWebPFile::Open(this, strFileName, m_bIsRGBA);
}
#endif
NSFile::CFileBinary oFile;
if (!oFile.OpenFile(strFileName))
return false;
@ -552,6 +563,13 @@ bool CBgraFrame::Decode(BYTE* pBuffer, int nSize, unsigned int nFileType)
}
#endif
#if CXIMAGE_SUPPORT_WEBP
if (CXIMAGE_FORMAT_WEBP == m_nFileType)
{
return NSWebP::CWebPFile::Open(this, pBuffer, nSize, m_bIsRGBA);
}
#endif
CxImage img;
if (!img.Decode(pBuffer, nSize, m_nFileType))
@ -588,6 +606,13 @@ bool CBgraFrame::SaveFile(const std::wstring& strFileName, unsigned int nFileTyp
}
#endif
#if CXIMAGE_SUPPORT_WEBP
if (CXIMAGE_FORMAT_WEBP == nFileType)
{
return NSWebP::CWebPFile::Save(m_pData, m_lWidth, m_lHeight, strFileName, m_bIsRGBA);
}
#endif
NSFile::CFileBinary oFile;
if (!oFile.CreateFileW(strFileName))
return false;

View File

@ -35,6 +35,9 @@
#if CXIMAGE_SUPPORT_HEIF
#include "heif/heif.h"
#endif
#if CXIMAGE_SUPPORT_WEBP
#include "WebP/webp.h"
#endif
#ifndef IMAGE_CHECKER_DISABLE_XML
#include "../xml/include/xmlutils.h"
@ -444,6 +447,15 @@ bool CImageFileFormatChecker::isHeifFile(BYTE* pBuffer, DWORD dwBytes)
return false;
#endif
}
bool CImageFileFormatChecker::isWebPFile(BYTE* pBuffer, DWORD dwBytes)
{
#if CXIMAGE_SUPPORT_WEBP
return NSWebP::CWebPFile::isWebP(pBuffer, dwBytes);
#else
return false;
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool CImageFileFormatChecker::isImageFile(const std::wstring& fileName)
{
@ -570,6 +582,10 @@ bool CImageFileFormatChecker::isImageFile(const std::wstring& fileName)
{
eFileType = _CXIMAGE_FORMAT_HEIF;
}
else if (isWebPFile(fileName))
{
eFileType = _CXIMAGE_FORMAT_WEBP;
}
///////////////////////////////////////////////////////////////////////
delete [] buffer;
@ -689,6 +705,10 @@ bool CImageFileFormatChecker::isImageFile(BYTE* buffer, DWORD sizeRead)
{
eFileType = _CXIMAGE_FORMAT_HEIF;
}
if (isWebPFile(buffer, sizeRead))
{
eFileType = _CXIMAGE_FORMAT_WEBP;
}
///////////////////////////////////////////////////////////////////////
if (eFileType) return true;
return false;
@ -815,6 +835,15 @@ bool CImageFileFormatChecker::isHeifFile(const std::wstring& fileName)
#endif
}
bool CImageFileFormatChecker::isWebPFile(const std::wstring& fileName)
{
#if CXIMAGE_SUPPORT_WEBP
return NSWebP::CWebPFile::isWebP(fileName);
#else
return false;
#endif
}
std::wstring CImageFileFormatChecker::DetectFormatByData(BYTE *Data, int DataSize)
{
if (isBmpFile(Data,DataSize)) return L"bmp";

View File

@ -64,6 +64,7 @@ enum __ENUM_CXIMAGE_FORMATS
_CXIMAGE_FORMAT_SVG = 24,
_CXIMAGE_FORMAT_PIC = 25,
_CXIMAGE_FORMAT_HEIF = 26,
_CXIMAGE_FORMAT_WEBP = 27,
};
class GRAPHICS_DECL CImageFileFormatChecker
@ -84,6 +85,7 @@ public:
bool isRawFile(const std::wstring& fileName);
bool isSvgFile(const std::wstring& fileName);
bool isHeifFile(const std::wstring& fileName);
bool isWebPFile(const std::wstring& fileName);
bool isImageFile(BYTE* pBuffer,DWORD dwBytes);
bool isBmpFile(BYTE* pBuffer,DWORD dwBytes);
@ -114,6 +116,7 @@ public:
bool isRawFile(BYTE* pBuffer,DWORD dwBytes);
bool isPicFile(BYTE* pBuffer,DWORD dwBytes);
bool isHeifFile(BYTE* pBuffer, DWORD dwBytes);
bool isWebPFile(BYTE* pBuffer, DWORD dwBytes);
std::wstring DetectFormatByData(BYTE *Data, int DataSize);

View File

@ -0,0 +1,273 @@
#include "webp.h"
#include "../../common/File.h"
#include "../../Common/3dParty/webp/libwebp/src/webp/decode.h"
#include "../../Common/3dParty/webp/libwebp/src/webp/encode.h"
#include <limits>
#include <memory>
namespace NSWebP {
constexpr int MAX_INT_SIZE = std::numeric_limits<int32_t>::max();
constexpr int BUFFER_SIZE = 4096;
class CWebPFile::Stream
{
public:
Stream() {}
Stream(FILE *_file) : file(_file) {}
Stream(BYTE *_buffer, const DWORD& _size) : buffer(_buffer), size(_size) {}
size_t Read(BYTE *data) {
if (file)
return fread(data, 1, BUFFER_SIZE, file);
else if (buffer && size > 0 && cur < size) {
DWORD tmp_size = size < BUFFER_SIZE ? size : BUFFER_SIZE;
memcpy(data, buffer + cur, tmp_size);
cur = tmp_size;
return tmp_size;
} else
return 0;
}
private:
FILE* file{nullptr};
BYTE* buffer{nullptr};
DWORD size{0};
DWORD cur{0};
};
static int writeFunc(const BYTE* data, size_t size, const WebPPicture* picture)
{
FILE* file = static_cast<FILE*>(picture->custom_ptr);
return fwrite(data, 1, size, file);
}
bool CWebPFile::isWebP(const std::wstring& fileName)
{
NSFile::CFileBinary file;
if (!file.OpenFile(fileName))
return false;
BYTE data[4];
fseek(file.GetFileNative(), 8, SEEK_CUR);
int bytes_read = fread(&data, 1, 4, file.GetFileNative());
if (bytes_read < 4)
{
file.CloseFile();
return false;
}
if (strncmp((const char*) data, "WEBP", 4) != 0)
{
file.CloseFile();
return false;
}
file.CloseFile();
return true;
}
bool CWebPFile::isWebP(BYTE* buffer, const DWORD& size)
{
if (size < 12)
return false;
if (strncmp((const char*) buffer + 8, "WEBP", 4) != 0)
return false;
return true;
}
bool CWebPFile::Open(CBgraFrame* frame, const std::wstring& fileName, bool isRGBA)
{
NSFile::CFileBinary file;
if (!file.OpenFile(fileName))
return false;
Stream* stream = new Stream(file.GetFileNative());
auto status = Decode(stream, frame, isRGBA);
delete stream;
file.CloseFile();
return status;
}
bool CWebPFile::Open(CBgraFrame* frame, BYTE* buffer, const DWORD& size, bool isRGBA)
{
Stream* stream = new Stream(buffer, size);
auto status = Decode(stream, frame, isRGBA);
delete stream;
return status;
}
bool CWebPFile::Save(const BYTE* source, int width, int height, const std::wstring& dstPath, bool isRGBA)
{
if (!source)
return false;
WebPConfig cfg;
if (!WebPConfigInit(&cfg))
return false;
if (!WebPConfigLosslessPreset(&cfg, 6))
return false;
if (!WebPValidateConfig(&cfg))
return false;
WebPPicture pct;
if (!WebPPictureInit(&pct))
return false;
pct.width = width;
pct.height = height;
pct.use_argb = 1;
if (!WebPPictureAlloc(&pct))
{
WebPPictureFree(&pct);
return false;
}
std::vector<BYTE> data(width * height * 4);
for (size_t i = 0; i < height; ++i)
{
BYTE* dst = data.data() + width * 4 * i;
const BYTE* src = source + width * 4 * (height - i - 1);
for (size_t j = 0; j < width; ++j)
{
dst[0] = src[j * 4 + 0];
dst[1] = src[j * 4 + 1];
dst[2] = src[j * 4 + 2];
dst[3] = src[j * 4 + 3];
dst += 4;
}
}
if (!(isRGBA ? WebPPictureImportRGBA(&pct, data.data(), width * 4) : WebPPictureImportBGRA(&pct, data.data(), width * 4)))
{
WebPPictureFree(&pct);
return false;
}
NSFile::CFileBinary file;
file.CreateFile(dstPath);
pct.writer = writeFunc;
pct.custom_ptr = file.GetFileNative();
return WebPEncode(&cfg, &pct);
}
bool CWebPFile::Decode(Stream* stream, CBgraFrame* frame, bool isRGBA)
{
WebPDecoderConfig cfg;
if (!WebPInitDecoderConfig(&cfg))
return false;
std::vector<BYTE> data;
while(true)
{
size_t last_size = data.size();
data.resize(last_size + BUFFER_SIZE);
auto bytes_read = stream->Read(data.data() + last_size);
if (bytes_read <= 0)
{
WebPFreeDecBuffer(&cfg.output);
return false;
}
data.resize(last_size + bytes_read);
auto status = WebPGetFeatures(data.data(), data.size(), &cfg.input);
if (status == VP8_STATUS_OK)
break;
if (status == VP8_STATUS_NOT_ENOUGH_DATA)
continue;
WebPFreeDecBuffer(&cfg.output);
return false;
}
const int& width = cfg.input.width;
const int& height = cfg.input.height;
const int& has_alpha = cfg.input.has_alpha;
if (width > MAX_INT_SIZE / 8 || height > MAX_INT_SIZE / 8)
{
WebPFreeDecBuffer(&cfg.output);
return false;
}
cfg.output.width = width;
cfg.output.height = height;
cfg.output.is_external_memory = 1;
std::vector<BYTE> tmp_rgba_data(width * height * 4);
if (has_alpha)
{
if (isRGBA)
cfg.output.colorspace = MODE_RGBA;
else
cfg.output.colorspace = MODE_BGRA;
}
else
{
if (isRGBA)
cfg.output.colorspace = MODE_RGB;
else
cfg.output.colorspace = MODE_BGR;
}
cfg.output.u.RGBA.rgba = tmp_rgba_data.data();
cfg.output.u.RGBA.stride = width * 4;
cfg.output.u.RGBA.size = tmp_rgba_data.size();
bool success = true;
std::unique_ptr<WebPIDecoder, decltype(&WebPIDelete)> decoder(WebPIDecode(nullptr, 0, &cfg), WebPIDelete);
while(true)
{
auto status = WebPIAppend(decoder.get(), data.data(), data.size());
if (status == VP8_STATUS_OK)
break;
if (status != VP8_STATUS_SUSPENDED)
{
success = false;
break;
}
data.resize(BUFFER_SIZE);
auto bytes_read = stream->Read(data.data());
if (bytes_read <= 0)
{
success = false;
break;
}
data.resize(bytes_read);
}
BYTE* frame_data = new BYTE[width * height * 4];
frame->put_Data(frame_data);
frame->put_Width(width);
frame->put_Height(height);
frame->put_Stride(4 * width);
for (size_t i = 0; i < height; ++i)
{
const BYTE* row = tmp_rgba_data.data() + width * 4 * i;
for (size_t j = 0; j < width; ++j)
{
frame_data[(i * width + j) * 4 + 0] = row[0];
frame_data[(i * width + j) * 4 + 1] = row[1];
frame_data[(i * width + j) * 4 + 2] = row[2];
frame_data[(i * width + j) * 4 + 3] = has_alpha ? row[3] : 255;
row += has_alpha ? 4 : 3;
}
}
WebPFreeDecBuffer(&cfg.output);
return success;
}
}

View File

@ -0,0 +1,27 @@
#ifndef WEBP_H
#define WEBP_H
#include "../../graphics/pro/Graphics.h"
namespace NSWebP {
class CWebPFile
{
private:
class Stream;
private:
CWebPFile() = delete;
public:
static bool isWebP(const std::wstring& fileName);
static bool isWebP(BYTE* buffer, const DWORD& size);
static bool Open(CBgraFrame* frame, const std::wstring& fileName, bool isRGBA);
static bool Open(CBgraFrame* frame, BYTE* buffer, const DWORD& size, bool isRGBA);
static bool Save(const BYTE* source, int width, int height, const std::wstring& dstPath, bool isRGBA);
private:
static bool Decode(Stream* stream, CBgraFrame* frame, bool isRGBA);
};
}
#endif