diff --git a/DesktopEditor/cximage/CxImage/ximacfg.h b/DesktopEditor/cximage/CxImage/ximacfg.h index d6189f4bdc..2d3ee55be5 100644 --- a/DesktopEditor/cximage/CxImage/ximacfg.h +++ b/DesktopEditor/cximage/CxImage/ximacfg.h @@ -38,6 +38,7 @@ #define CXIMAGE_SUPPORT_PNM 1 #define CXIMAGE_SUPPORT_RAS 1 #define CXIMAGE_SUPPORT_PIC 1 +#define CXIMAGE_SUPPORT_HEIF 1 #define CXIMAGE_SUPPORT_JBG 0 // GPL'd see ../jbig/copying.txt & ../jbig/patents.htm diff --git a/DesktopEditor/cximage/CxImage/ximage.h b/DesktopEditor/cximage/CxImage/ximage.h index 4ac5415f81..ab0ce0aaff 100644 --- a/DesktopEditor/cximage/CxImage/ximage.h +++ b/DesktopEditor/cximage/CxImage/ximage.h @@ -133,13 +133,17 @@ CXIMAGE_FORMAT_PSD = 20, #if CXIMAGE_SUPPORT_PIC CXIMAGE_FORMAR_PIC = 25, #endif +#if CXIMAGE_SUPPORT_HEIF +CXIMAGE_FORMAT_HEIF = 26, +#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 + CXIMAGE_SUPPORT_WBMP+ CXIMAGE_SUPPORT_WMF + CXIMAGE_SUPPORT_PIC + 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 + 1 + CXIMAGE_SUPPORT_SKA + CXIMAGE_SUPPORT_RAW + CXIMAGE_SUPPORT_PSD + + CXIMAGE_SUPPORT_HEIF + 1 }; #if CXIMAGE_SUPPORT_EXIF diff --git a/DesktopEditor/cximage/tiff/tif_getimage.c b/DesktopEditor/cximage/tiff/tif_getimage.c index c30b2b0490..b87e7476da 100644 --- a/DesktopEditor/cximage/tiff/tif_getimage.c +++ b/DesktopEditor/cximage/tiff/tif_getimage.c @@ -23,14 +23,14 @@ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ - -#pragma warning (disable : 4550) + +#pragma warning (disable : 4550) /* * TIFF Library * * Read and return a packed RGBA image. - */ + */ #include "tiffiop.h" #include @@ -828,11 +828,12 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) nrowsub = nrow; if ((nrowsub%subsamplingver)!=0) nrowsub+=subsamplingver-nrowsub%subsamplingver; + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif,row+img->row_offset, 0), buf, - ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline) < 0 - && img->stoponerr) + ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline) < 0 + && img->stoponerr) { ret = 0; break; diff --git a/DesktopEditor/graphics/pro/raster.pri b/DesktopEditor/graphics/pro/raster.pri index 28d4b2d2d8..7218569003 100644 --- a/DesktopEditor/graphics/pro/raster.pri +++ b/DesktopEditor/graphics/pro/raster.pri @@ -39,7 +39,8 @@ core_android { INCLUDEPATH += \ $$LIB_GRAPHICS_PRI_PATH/cximage/jasper/include \ $$LIB_GRAPHICS_PRI_PATH/cximage/jpeg \ - $$LIB_GRAPHICS_PRI_PATH/cximage/png + $$LIB_GRAPHICS_PRI_PATH/cximage/png \ + $$LIB_GRAPHICS_PRI_PATH/../Common/3dParty/heif/libheif/libheif/api \ HEADERS += \ $$PWD/../../graphics/Image.h \ @@ -285,6 +286,9 @@ SOURCES += \ $$LIB_GRAPHICS_PRI_PATH/raster/PICT/PICFile.cpp \ $$LIB_GRAPHICS_PRI_PATH/raster/PICT/pic.cpp +SOURCES += \ + $$LIB_GRAPHICS_PRI_PATH/raster/heif/heif.cpp + SOURCES += \ $$LIB_GRAPHICS_PRI_PATH/cximage/jasper/base/jas_cm.c \ $$LIB_GRAPHICS_PRI_PATH/cximage/jasper/base/jas_debug.c \ diff --git a/DesktopEditor/raster/BgraFrame.cpp b/DesktopEditor/raster/BgraFrame.cpp index d39f05fddd..f79fe535b2 100644 --- a/DesktopEditor/raster/BgraFrame.cpp +++ b/DesktopEditor/raster/BgraFrame.cpp @@ -44,6 +44,10 @@ #include "PICT/PICFile.h" #endif +#if CXIMAGE_SUPPORT_HEIF +#include "heif/heif.h" +#endif + #include #define BGRA_FRAME_CXIMAGE_MAX_MEMORY 67108864 // 256Mb (*4 channel) @@ -444,11 +448,18 @@ bool CBgraFrame::OpenFile(const std::wstring& strFileName, unsigned int nFileTyp #endif #if CXIMAGE_SUPPORT_PIC - if (CXIMAGE_FORMAR_PIC == m_nFileType) - { - PICT::CPictFile PIC; - return PIC.Open(this, strFileName, !m_bIsRGBA); - } + if (CXIMAGE_FORMAR_PIC == m_nFileType) + { + PICT::CPictFile PIC; + return PIC.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; @@ -534,6 +545,13 @@ bool CBgraFrame::Decode(BYTE* pBuffer, int nSize, unsigned int nFileType) } #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)) diff --git a/DesktopEditor/raster/ImageFileFormatChecker.cpp b/DesktopEditor/raster/ImageFileFormatChecker.cpp index 020119a96c..ba6cca7861 100644 --- a/DesktopEditor/raster/ImageFileFormatChecker.cpp +++ b/DesktopEditor/raster/ImageFileFormatChecker.cpp @@ -32,6 +32,7 @@ #include "ImageFileFormatChecker.h" #include "../common/File.h" #include "../cximage/CxImage/ximacfg.h" +#include "heif/heif.h" #ifndef IMAGE_CHECKER_DISABLE_XML #include "../xml/include/xmlutils.h" @@ -432,6 +433,11 @@ bool CImageFileFormatChecker::isPicFile(BYTE *pBuffer, DWORD dwBytes) return false; } + +bool CImageFileFormatChecker::isHeifFile(BYTE* pBuffer, DWORD dwBytes) +{ + return NSHeif::CHeifFile::isHeif(pBuffer, dwBytes); +} ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool CImageFileFormatChecker::isImageFile(const std::wstring& fileName) { @@ -554,6 +560,10 @@ bool CImageFileFormatChecker::isImageFile(const std::wstring& fileName) { eFileType = _CXIMAGE_FORMAT_PIC; } + else if (isHeifFile(fileName)) + { + eFileType = _CXIMAGE_FORMAT_HEIF; + } /////////////////////////////////////////////////////////////////////// delete [] buffer; @@ -669,6 +679,10 @@ bool CImageFileFormatChecker::isImageFile(BYTE* buffer, DWORD sizeRead) { eFileType = _CXIMAGE_FORMAT_PIC; } + if (isHeifFile(buffer, sizeRead)) + { + eFileType = _CXIMAGE_FORMAT_HEIF; + } /////////////////////////////////////////////////////////////////////// if (eFileType) return true; return false; @@ -786,6 +800,10 @@ bool CImageFileFormatChecker::isSvgFile(const std::wstring& fileName) return bFind; #endif } +bool CImageFileFormatChecker::isHeifFile(const std::wstring& fileName) +{ + return NSHeif::CHeifFile::isHeif(fileName); +} std::wstring CImageFileFormatChecker::DetectFormatByData(BYTE *Data, int DataSize) { diff --git a/DesktopEditor/raster/ImageFileFormatChecker.h b/DesktopEditor/raster/ImageFileFormatChecker.h index 51c06178de..6cbf6df80b 100644 --- a/DesktopEditor/raster/ImageFileFormatChecker.h +++ b/DesktopEditor/raster/ImageFileFormatChecker.h @@ -63,6 +63,7 @@ enum __ENUM_CXIMAGE_FORMATS _CXIMAGE_FORMAT_SVM = 23, _CXIMAGE_FORMAT_SVG = 24, _CXIMAGE_FORMAT_PIC = 25, + _CXIMAGE_FORMAT_HEIF = 26, }; class GRAPHICS_DECL CImageFileFormatChecker @@ -82,6 +83,7 @@ public: bool isRawFile(const std::wstring& fileName); bool isSvgFile(const std::wstring& fileName); + bool isHeifFile(const std::wstring& fileName); bool isImageFile(BYTE* pBuffer,DWORD dwBytes); bool isBmpFile(BYTE* pBuffer,DWORD dwBytes); @@ -111,6 +113,7 @@ public: bool isSvgFile(BYTE* pBuffer,DWORD dwBytes); bool isRawFile(BYTE* pBuffer,DWORD dwBytes); bool isPicFile(BYTE* pBuffer,DWORD dwBytes); + bool isHeifFile(BYTE* pBuffer, DWORD dwBytes); std::wstring DetectFormatByData(BYTE *Data, int DataSize); diff --git a/DesktopEditor/raster/heif/heif.cpp b/DesktopEditor/raster/heif/heif.cpp new file mode 100644 index 0000000000..3e1680af90 --- /dev/null +++ b/DesktopEditor/raster/heif/heif.cpp @@ -0,0 +1,122 @@ +#include "heif.h" +#include "../../Common/3dParty/heif/libheif/libheif/api/libheif/heif.h" +#include "../../UnicodeConverter/UnicodeConverter.h" +#include "../../common/File.h" + +namespace NSHeif { + bool CHeifFile::isHeif(const std::wstring& fileName) + { + NSUnicodeConverter::CUnicodeConverter converter; + + heif_context* ctx = heif_context_alloc(); + bool status = heif_context_read_from_file(ctx, converter.fromUnicode(fileName, "UTF-8").c_str(), nullptr).code == heif_error_Ok; + + heif_context_free(ctx); + return status; + } + + bool CHeifFile::isHeif(BYTE* buffer, size_t size) + { + NSFile::CFileBinary file; + std::wstring tmp_file = NSFile::CFileBinary::CreateTempFileWithUniqueName(NSFile::CFileBinary::GetTempPath(), L"heif"); + + if (!file.CreateFile(tmp_file)) + return false; + + file.WriteFile(buffer, size); + file.CloseFile(); + + return isHeif(tmp_file); + } + + bool CHeifFile::Open(CBgraFrame *frame, const std::wstring& fileName, bool isRGBA) + { + NSUnicodeConverter::CUnicodeConverter converter; + + heif_context* ctx = heif_context_alloc(); + if (heif_context_read_from_file(ctx, converter.fromUnicode(fileName, "UTF-8").c_str(), nullptr).code != heif_error_Ok) + return false; + + heif_image_handle* handle; + if (heif_context_get_primary_image_handle(ctx, &handle).code != heif_error_Ok) + return false; + + heif_image* img; + if (heif_decode_image(handle, &img, heif_colorspace_RGB, heif_chroma_interleaved_RGB, nullptr).code != heif_error_Ok) + return false; + + int width = heif_image_get_primary_width(img); + int height = heif_image_get_primary_height(img); + + int stride; + const BYTE* source = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride); + + if (stride == 0 || source == nullptr) + return false; + + BYTE* data = new BYTE[stride * height]; + + frame->put_Width(width); + frame->put_Height(height); + frame->put_Stride(stride); + frame->put_Data(data); + frame->put_IsRGBA(isRGBA); + memcpy(data, source, stride * height); + + heif_image_release(img); + heif_image_handle_release(handle); + heif_context_free(ctx); + + return true; + } + + bool CHeifFile::Open(CBgraFrame *frame, BYTE* buffer, size_t size, bool isRGBA) + { + NSFile::CFileBinary file; + std::wstring tmp_file = NSFile::CFileBinary::CreateTempFileWithUniqueName(NSFile::CFileBinary::GetTempPath(), L"heif"); + + if (!file.CreateFile(tmp_file)) + return false; + + file.WriteFile(buffer, size); + file.CloseFile(); + + bool status = false; + if (Open(frame, tmp_file, isRGBA)) + status = true; + + if (NSFile::CFileBinary::Exists(tmp_file)) + NSFile::CFileBinary::Remove(tmp_file); + + return status; + } + + bool CHeifFile::Save(CBgraFrame *frame, const std::wstring& dstPath) + { + if (!frame) + return false; + + heif_context* ctx = heif_context_alloc(); + heif_encoder* encoder; + if (heif_context_get_encoder_for_format(ctx, heif_compression_HEVC, &encoder).code != heif_error_Ok) + return false; + + if (heif_encoder_set_lossy_quality(encoder, 50).code != heif_error_Ok) + return false; + + heif_image* img; + if (heif_context_encode_image(ctx, img, encoder, nullptr, nullptr).code != heif_error_Ok) + return false; + + heif_encoder_release(encoder); + + NSUnicodeConverter::CUnicodeConverter converter; + + if (heif_context_write_to_file(ctx, converter.fromUnicode(dstPath, "UTF-8").c_str()).code != heif_error_Ok) + return false; + + heif_context_free(ctx); + + return true; + } +} diff --git a/DesktopEditor/raster/heif/heif.h b/DesktopEditor/raster/heif/heif.h new file mode 100644 index 0000000000..eb5c1f2608 --- /dev/null +++ b/DesktopEditor/raster/heif/heif.h @@ -0,0 +1,15 @@ +#include "../BgraFrame.h" + +namespace NSHeif { + class GRAPHICS_DECL CHeifFile { + private: + CHeifFile() = delete; + public: + static bool isHeif(const std::wstring& fileName); + static bool isHeif(BYTE* buffer, size_t size); + + static bool Open(CBgraFrame* frame, const std::wstring& fileName, bool isRGBA); + static bool Open(CBgraFrame* frame, BYTE* buffer, size_t size, bool isRGBA); + static bool Save(CBgraFrame* frame, const std::wstring& dstPath); + }; +}