diff --git a/others/C++/Image_format_converter/CMakeLists.txt b/others/C++/Image_format_converter/CMakeLists.txt index bf9ed48..5e3aa93 100644 --- a/others/C++/Image_format_converter/CMakeLists.txt +++ b/others/C++/Image_format_converter/CMakeLists.txt @@ -1,60 +1,77 @@ -cmake_minimum_required(VERSION 3.10) -project(ImageFormatConverter) - -# 设置静态编译 -set(CMAKE_EXE_LINKER_FLAGS "-static") -set(BUILD_SHARED_LIBS OFF) -set(CMAKE_FIND_LIBRARY_SUFFIXES .a) - -# 设置C++标准 -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -# 查找依赖库(静态版本) -find_package(PkgConfig REQUIRED) -pkg_check_modules(TIFF REQUIRED libtiff-4) -find_library(TIFF_STATIC_LIB NAMES libtiff.a PATHS ${TIFF_LIBRARY_DIRS}) - -pkg_check_modules(WEBP REQUIRED libwebp) -find_library(WEBP_STATIC_LIB NAMES libwebp.a PATHS ${WEBP_LIBRARY_DIRS}) - -# 使用find_package查找FLTK(静态版本) -find_package(FLTK REQUIRED) -find_library(FLTK_STATIC_LIB NAMES libfltk.a PATHS ${FLTK_LIBRARY_DIRS}) - -# 包含头文件目录 -include_directories(include ${TIFF_INCLUDE_DIRS} ${WEBP_INCLUDE_DIRS} ${FLTK_INCLUDE_DIRS}) - -# 收集所有源文件 -file(GLOB SOURCES "src/*.cpp") - -# 创建可执行文件(设置为WIN32应用程序避免控制台窗口) -add_executable(ImageFormatConverter WIN32 ${SOURCES}) - -# 查找更多依赖库 -find_library(JPEG_STATIC_LIB NAMES libjpeg.a) -find_library(ZLIB_STATIC_LIB NAMES libz.a) -find_library(ZSTD_STATIC_LIB NAMES libzstd.a) -find_library(SHARPYUV_STATIC_LIB NAMES libsharpyuv.a) -find_library(JBIG_STATIC_LIB NAMES libjbig.a) -find_library(LZMA_STATIC_LIB NAMES liblzma.a) -find_library(LIBDEFLATE_STATIC_LIB NAMES libdeflate.a) -find_library(LERC_STATIC_LIB NAMES liblerc.a) - -# 链接静态库 -target_link_libraries(ImageFormatConverter - ${TIFF_STATIC_LIB} - ${WEBP_STATIC_LIB} - ${FLTK_STATIC_LIB} - ${JPEG_STATIC_LIB} - ${ZLIB_STATIC_LIB} - ${ZSTD_STATIC_LIB} - ${SHARPYUV_STATIC_LIB} - ${JBIG_STATIC_LIB} - ${LZMA_STATIC_LIB} - ${LIBDEFLATE_STATIC_LIB} - ${LERC_STATIC_LIB} - -lstdc++ -lgcc -lwinpthread -lcomctl32 -lole32 -luuid -lws2_32) - -# 设置输出目录 -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) +cmake_minimum_required(VERSION 3.10) +project(ImageFormatConverter) + +# 设置静态编译 +set(CMAKE_EXE_LINKER_FLAGS "-static") +set(BUILD_SHARED_LIBS OFF) +set(CMAKE_FIND_LIBRARY_SUFFIXES .a) + +# 设置C++标准 +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# 设置MSYS2库搜索路径 +set(MSYS2_LIB_DIR "C:/msys64/ucrt64/lib") + +# 查找依赖库(静态版本) +find_package(PkgConfig REQUIRED) +pkg_check_modules(TIFF REQUIRED libtiff-4) +find_library(TIFF_STATIC_LIB NAMES libtiff.a PATHS ${TIFF_LIBRARY_DIRS}) + +pkg_check_modules(WEBP REQUIRED libwebp) +find_library(WEBP_STATIC_LIB NAMES libwebp.a PATHS ${WEBP_LIBRARY_DIRS}) + +pkg_check_modules(AVIF REQUIRED libavif) +find_library(AVIF_STATIC_LIB NAMES libavif.a PATHS ${AVIF_LIBRARY_DIRS}) + +# 使用find_package查找FLTK(静态版本) +find_package(FLTK REQUIRED) +find_library(FLTK_STATIC_LIB NAMES libfltk.a PATHS ${FLTK_LIBRARY_DIRS}) + +# 查找其他依赖库 +find_library(JPEG_STATIC_LIB NAMES libjpeg.a PATHS ${MSYS2_LIB_DIR}) +find_library(ZLIB_STATIC_LIB NAMES libz.a PATHS ${MSYS2_LIB_DIR}) +find_library(ZSTD_STATIC_LIB NAMES libzstd.a PATHS ${MSYS2_LIB_DIR}) +find_library(SHARPYUV_STATIC_LIB NAMES libsharpyuv.a PATHS ${MSYS2_LIB_DIR}) +find_library(JBIG_STATIC_LIB NAMES libjbig.a PATHS ${MSYS2_LIB_DIR}) +find_library(LZMA_STATIC_LIB NAMES liblzma.a PATHS ${MSYS2_LIB_DIR}) +find_library(LIBDEFLATE_STATIC_LIB NAMES libdeflate.a PATHS ${MSYS2_LIB_DIR}) +find_library(LERC_STATIC_LIB NAMES liblerc.a PATHS ${MSYS2_LIB_DIR}) +find_library(AOM_STATIC_LIB NAMES libaom.a PATHS ${MSYS2_LIB_DIR}) +find_library(YUV_STATIC_LIB NAMES libyuv.a PATHS ${MSYS2_LIB_DIR}) +find_library(SVTAV1_ENC_STATIC_LIB NAMES libSvtAv1Enc.a PATHS ${MSYS2_LIB_DIR}) +find_library(RAV1E_STATIC_LIB NAMES librav1e.a PATHS ${MSYS2_LIB_DIR}) +find_library(DAV1D_STATIC_LIB NAMES libdav1d.a PATHS ${MSYS2_LIB_DIR}) + +# 包含头文件目录 +include_directories(include ${TIFF_INCLUDE_DIRS} ${WEBP_INCLUDE_DIRS} ${FLTK_INCLUDE_DIRS} ${AVIF_INCLUDE_DIRS}) + +# 收集所有源文件 +file(GLOB SOURCES "src/*.cpp") + +# 创建可执行文件(设置为WIN32应用程序避免控制台窗口) +add_executable(ImageFormatConverter WIN32 ${SOURCES}) + +# 链接静态库 +target_link_libraries(ImageFormatConverter + ${TIFF_STATIC_LIB} + ${WEBP_STATIC_LIB} + ${FLTK_STATIC_LIB} + ${JPEG_STATIC_LIB} + ${ZLIB_STATIC_LIB} + ${ZSTD_STATIC_LIB} + ${SHARPYUV_STATIC_LIB} + ${JBIG_STATIC_LIB} + ${LZMA_STATIC_LIB} + ${LIBDEFLATE_STATIC_LIB} + ${LERC_STATIC_LIB} + ${AVIF_STATIC_LIB} + ${AOM_STATIC_LIB} + ${YUV_STATIC_LIB} + ${SVTAV1_ENC_STATIC_LIB} + ${RAV1E_STATIC_LIB} + ${DAV1D_STATIC_LIB} + -lstdc++ -lgcc -lwinpthread -lcomctl32 -lole32 -luuid -lws2_32 -lntdll) + +# 设置输出目录 +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) diff --git a/others/C++/Image_format_converter/Makefile b/others/C++/Image_format_converter/Makefile deleted file mode 100644 index 98b18b0..0000000 --- a/others/C++/Image_format_converter/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -CXX = g++ -CXXFLAGS = -I"C:/msys64/ucrt64/include" -I"./include" -std=c++17 -Wall -mwindows -LDFLAGS = -L"C:/msys64/ucrt64/lib" -lfltk -lfltk_images -ltiff -ljpeg -lz -lzstd -lwebp -llerc -ljbig -llzma -ldeflate -lsharpyuv -lcomctl32 -lgdi32 -lole32 -luuid -lws2_32 -lwinspool -lcomdlg32 -static - -SRC = src/main.cpp src/gui.cpp src/utils.cpp src/stb_impl.cpp \ - src/png_to_jpg.cpp src/jpg_to_png.cpp src/image_loader.cpp \ - src/bmp_to_png.cpp src/bmp_to_jpg.cpp src/png_to_bmp.cpp \ - src/jpg_to_bmp.cpp src/tiff_to_bmp.cpp src/bmp_to_tiff.cpp \ - src/tiff_to_png.cpp src/png_to_tiff.cpp src/tiff_to_jpg.cpp \ - src/jpg_to_tiff.cpp src/webp_to_jpg.cpp src/webp_to_png.cpp \ - src/webp_to_bmp.cpp src/webp_to_tiff.cpp src/jpg_to_webp.cpp \ - src/png_to_webp.cpp src/bmp_to_webp.cpp src/tiff_to_webp.cpp \ - src/jpeg_to_png.cpp src/jpeg_to_bmp.cpp src/jpeg_to_tiff.cpp \ - src/jpeg_to_webp.cpp src/png_to_jpeg.cpp src/bmp_to_jpeg.cpp \ - src/tiff_to_jpeg.cpp src/webp_to_jpeg.cpp -OBJ = $(SRC:src/%.cpp=obj/%.o) -TARGET = image_converter - -all: $(TARGET) - -$(TARGET): $(OBJ) - $(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS) - -obj/%.o: src/%.cpp - $(CXX) $(CXXFLAGS) -c $< -o $@ - -clean: - rm -f $(OBJ) $(TARGET) - -.PHONY: all clean diff --git a/others/C++/Image_format_converter/include/avif_to_bmp.hpp b/others/C++/Image_format_converter/include/avif_to_bmp.hpp new file mode 100644 index 0000000..b243f1b --- /dev/null +++ b/others/C++/Image_format_converter/include/avif_to_bmp.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class AvifToBmpConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/avif_to_jpeg.hpp b/others/C++/Image_format_converter/include/avif_to_jpeg.hpp new file mode 100644 index 0000000..5428337 --- /dev/null +++ b/others/C++/Image_format_converter/include/avif_to_jpeg.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class AvifToJpegConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/avif_to_jpg.hpp b/others/C++/Image_format_converter/include/avif_to_jpg.hpp new file mode 100644 index 0000000..996ac98 --- /dev/null +++ b/others/C++/Image_format_converter/include/avif_to_jpg.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class AvifToJpgConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/avif_to_png.hpp b/others/C++/Image_format_converter/include/avif_to_png.hpp new file mode 100644 index 0000000..9e1c77b --- /dev/null +++ b/others/C++/Image_format_converter/include/avif_to_png.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class AvifToPngConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/avif_to_tiff.hpp b/others/C++/Image_format_converter/include/avif_to_tiff.hpp new file mode 100644 index 0000000..74a1716 --- /dev/null +++ b/others/C++/Image_format_converter/include/avif_to_tiff.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class AvifToTiffConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/avif_to_webp.hpp b/others/C++/Image_format_converter/include/avif_to_webp.hpp new file mode 100644 index 0000000..42e4f08 --- /dev/null +++ b/others/C++/Image_format_converter/include/avif_to_webp.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class AvifToWebpConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/bmp_to_avif.hpp b/others/C++/Image_format_converter/include/bmp_to_avif.hpp new file mode 100644 index 0000000..1216790 --- /dev/null +++ b/others/C++/Image_format_converter/include/bmp_to_avif.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class BmpToAvifConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/common.hpp b/others/C++/Image_format_converter/include/common.hpp index 50bc33b..aae4f1c 100644 --- a/others/C++/Image_format_converter/include/common.hpp +++ b/others/C++/Image_format_converter/include/common.hpp @@ -18,6 +18,7 @@ enum class ImageFormat { JPG, TIFF, WEBP, + AVIF, UNKNOWN }; diff --git a/others/C++/Image_format_converter/include/image_loader.hpp b/others/C++/Image_format_converter/include/image_loader.hpp index cf2fce8..54daf8c 100644 --- a/others/C++/Image_format_converter/include/image_loader.hpp +++ b/others/C++/Image_format_converter/include/image_loader.hpp @@ -7,7 +7,7 @@ public: static ImageData load(const std::string& path); static bool save_png(const std::string& path, const ImageData& data); static bool save_jpg(const std::string& path, const ImageData& data, int quality = 90); + static void validate_image(const unsigned char* data, int width, int height); private: - static void validate_image(const unsigned char* data, int width, int height); }; diff --git a/others/C++/Image_format_converter/include/jpeg_to_avif.hpp b/others/C++/Image_format_converter/include/jpeg_to_avif.hpp new file mode 100644 index 0000000..9d5417f --- /dev/null +++ b/others/C++/Image_format_converter/include/jpeg_to_avif.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class JpegToAvifConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/jpg_to_avif.hpp b/others/C++/Image_format_converter/include/jpg_to_avif.hpp new file mode 100644 index 0000000..9581a81 --- /dev/null +++ b/others/C++/Image_format_converter/include/jpg_to_avif.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class JpgToAvifConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/png_to_avif.hpp b/others/C++/Image_format_converter/include/png_to_avif.hpp new file mode 100644 index 0000000..96061ee --- /dev/null +++ b/others/C++/Image_format_converter/include/png_to_avif.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class PngToAvifConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/tiff_to_avif.hpp b/others/C++/Image_format_converter/include/tiff_to_avif.hpp new file mode 100644 index 0000000..23dbd31 --- /dev/null +++ b/others/C++/Image_format_converter/include/tiff_to_avif.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class TiffToAvifConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/include/webp_to_avif.hpp b/others/C++/Image_format_converter/include/webp_to_avif.hpp new file mode 100644 index 0000000..7c9bf43 --- /dev/null +++ b/others/C++/Image_format_converter/include/webp_to_avif.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "converter_base.hpp" +#include "common.hpp" + +class WebpToAvifConverter : public ConverterBase { +public: + bool convert(const std::string& input, const std::string& output) override; + +protected: + bool validate(const ImageData& data) override; +}; diff --git a/others/C++/Image_format_converter/src/avif_to_bmp.cpp b/others/C++/Image_format_converter/src/avif_to_bmp.cpp new file mode 100644 index 0000000..030d11a --- /dev/null +++ b/others/C++/Image_format_converter/src/avif_to_bmp.cpp @@ -0,0 +1,31 @@ +#include "avif_to_bmp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool AvifToBmpConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载AVIF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 保存为BMP + return stbi_write_bmp(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get()); +} + +bool AvifToBmpConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/avif_to_jpeg.cpp b/others/C++/Image_format_converter/src/avif_to_jpeg.cpp new file mode 100644 index 0000000..05e6489 --- /dev/null +++ b/others/C++/Image_format_converter/src/avif_to_jpeg.cpp @@ -0,0 +1,32 @@ +#include "avif_to_jpeg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool AvifToJpegConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载AVIF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 保存为JPEG(默认质量90) + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + 90); +} + +bool AvifToJpegConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/avif_to_jpg.cpp b/others/C++/Image_format_converter/src/avif_to_jpg.cpp new file mode 100644 index 0000000..bd45cf0 --- /dev/null +++ b/others/C++/Image_format_converter/src/avif_to_jpg.cpp @@ -0,0 +1,32 @@ +#include "avif_to_jpg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool AvifToJpgConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载AVIF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 保存为JPG(默认质量90) + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + 90); +} + +bool AvifToJpgConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/avif_to_png.cpp b/others/C++/Image_format_converter/src/avif_to_png.cpp new file mode 100644 index 0000000..b85ef6a --- /dev/null +++ b/others/C++/Image_format_converter/src/avif_to_png.cpp @@ -0,0 +1,33 @@ +#include "avif_to_png.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool AvifToPngConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载AVIF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 保存为PNG + return stbi_write_png(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + data.width * data.channels); +} + +bool AvifToPngConverter::validate(const ImageData& data) { + // 确保是有效的图像数据 + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/avif_to_tiff.cpp b/others/C++/Image_format_converter/src/avif_to_tiff.cpp new file mode 100644 index 0000000..4ccc7c8 --- /dev/null +++ b/others/C++/Image_format_converter/src/avif_to_tiff.cpp @@ -0,0 +1,65 @@ +#include "avif_to_tiff.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool AvifToTiffConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载AVIF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 创建TIFF文件 + TIFF* tif = TIFFOpen(output_path.c_str(), "w"); + if (!tif) { + return false; + } + + // 设置TIFF标签 + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, data.width); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, data.height); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, data.channels); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, + (data.channels == 1) ? PHOTOMETRIC_MINISBLACK : + (data.channels == 3) ? PHOTOMETRIC_RGB : PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW); + + // 写入图像数据 + tsize_t linebytes = data.width * data.channels; + unsigned char* buf = nullptr; + if (TIFFScanlineSize(tif) == linebytes) { + buf = (unsigned char*)_TIFFmalloc(linebytes); + } else { + buf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(tif)); + } + + for (uint32_t row = 0; row < data.height; row++) { + memcpy(buf, &data.pixels.get()[row * linebytes], linebytes); + if (TIFFWriteScanline(tif, buf, row, 0) < 0) { + _TIFFfree(buf); + TIFFClose(tif); + return false; + } + } + + // 清理资源 + _TIFFfree(buf); + TIFFClose(tif); + return true; +} + +bool AvifToTiffConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 1 || data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/avif_to_webp.cpp b/others/C++/Image_format_converter/src/avif_to_webp.cpp new file mode 100644 index 0000000..0d4b3a4 --- /dev/null +++ b/others/C++/Image_format_converter/src/avif_to_webp.cpp @@ -0,0 +1,50 @@ +#include "avif_to_webp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool AvifToWebpConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载AVIF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 保存为WEBP + FILE* f = fopen(output_path.c_str(), "wb"); + if (!f) { + return false; + } + + uint8_t* output = nullptr; + size_t size = 0; + if (data.channels == 3) { + size = WebPEncodeRGB(data.pixels.get(), data.width, data.height, + data.width * 3, 90, &output); + } else if (data.channels == 4) { + size = WebPEncodeRGBA(data.pixels.get(), data.width, data.height, + data.width * 4, 90, &output); + } + + if (size == 0 || !output) { + fclose(f); + return false; + } + + fwrite(output, 1, size, f); + fclose(f); + WebPFree(output); + return true; +} + +bool AvifToWebpConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/bmp_to_avif.cpp b/others/C++/Image_format_converter/src/bmp_to_avif.cpp new file mode 100644 index 0000000..995f9d1 --- /dev/null +++ b/others/C++/Image_format_converter/src/bmp_to_avif.cpp @@ -0,0 +1,71 @@ +#include "bmp_to_avif.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool BmpToAvifConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载BMP图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 创建AVIF编码器 + avifEncoder* encoder = avifEncoderCreate(); + encoder->maxThreads = 4; + encoder->minQuantizer = 20; + encoder->maxQuantizer = 20; + encoder->speed = 6; + + // 创建AVIF图像 + avifImage* image = avifImageCreate(data.width, data.height, 8, AVIF_PIXEL_FORMAT_YUV420); + avifRGBImage rgbImage; + avifRGBImageSetDefaults(&rgbImage, image); + rgbImage.pixels = data.pixels.get(); + rgbImage.rowBytes = data.width * data.channels; + rgbImage.format = (data.channels == 3) ? AVIF_RGB_FORMAT_RGB : AVIF_RGB_FORMAT_RGBA; + + // 转换RGB到YUV + if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 编码AVIF图像 + avifRWData output = AVIF_DATA_EMPTY; + if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 保存AVIF文件 + FILE* f = fopen(output_path.c_str(), "wb"); + if (!f) { + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + fwrite(output.data, 1, output.size, f); + fclose(f); + + // 清理资源 + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return true; +} + +bool BmpToAvifConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/gui.cpp b/others/C++/Image_format_converter/src/gui.cpp index bcb6b2d..d4d817d 100644 --- a/others/C++/Image_format_converter/src/gui.cpp +++ b/others/C++/Image_format_converter/src/gui.cpp @@ -28,6 +28,18 @@ #include "bmp_to_jpeg.hpp" #include "tiff_to_jpeg.hpp" #include "webp_to_jpeg.hpp" +#include "avif_to_png.hpp" +#include "avif_to_jpg.hpp" +#include "avif_to_jpeg.hpp" +#include "avif_to_bmp.hpp" +#include "avif_to_tiff.hpp" +#include "avif_to_webp.hpp" +#include "png_to_avif.hpp" +#include "jpg_to_avif.hpp" +#include "jpeg_to_avif.hpp" +#include "bmp_to_avif.hpp" +#include "tiff_to_avif.hpp" +#include "webp_to_avif.hpp" #include #include #include @@ -77,6 +89,18 @@ MainWindow::MainWindow(int w, int h, const char* title) format_choice->add("BMP to JPEG"); format_choice->add("TIFF to JPEG"); format_choice->add("WEBP to JPEG"); + format_choice->add("AVIF to PNG"); + format_choice->add("AVIF to JPG"); + format_choice->add("AVIF to JPEG"); + format_choice->add("AVIF to BMP"); + format_choice->add("AVIF to TIFF"); + format_choice->add("AVIF to WEBP"); + format_choice->add("PNG to AVIF"); + format_choice->add("JPG to AVIF"); + format_choice->add("JPEG to AVIF"); + format_choice->add("BMP to AVIF"); + format_choice->add("TIFF to AVIF"); + format_choice->add("WEBP to AVIF"); format_choice->value(0); convert_btn = new Fl_Button(150, 150, 100, 30, "转换"); @@ -202,6 +226,42 @@ void MainWindow::convert_cb(Fl_Widget* w, void* data) { case 27: // WEBP to JPEG success = WebpToJpegConverter::convert(input, output); break; + case 28: // AVIF to PNG + success = AvifToPngConverter().convert(input, output); + break; + case 29: // AVIF to JPG + success = AvifToJpgConverter().convert(input, output); + break; + case 30: // AVIF to JPEG + success = AvifToJpegConverter().convert(input, output); + break; + case 31: // AVIF to BMP + success = AvifToBmpConverter().convert(input, output); + break; + case 32: // AVIF to TIFF + success = AvifToTiffConverter().convert(input, output); + break; + case 33: // AVIF to WEBP + success = AvifToWebpConverter().convert(input, output); + break; + case 34: // PNG to AVIF + success = PngToAvifConverter().convert(input, output); + break; + case 35: // JPG to AVIF + success = JpgToAvifConverter().convert(input, output); + break; + case 36: // JPEG to AVIF + success = JpegToAvifConverter().convert(input, output); + break; + case 37: // BMP to AVIF + success = BmpToAvifConverter().convert(input, output); + break; + case 38: // TIFF to AVIF + success = TiffToAvifConverter().convert(input, output); + break; + case 39: // WEBP to AVIF + success = WebpToAvifConverter().convert(input, output); + break; } if (!success) throw std::runtime_error("转换失败"); } catch (const std::exception& e) { diff --git a/others/C++/Image_format_converter/src/image_loader.cpp b/others/C++/Image_format_converter/src/image_loader.cpp index 267fe11..2eae243 100644 --- a/others/C++/Image_format_converter/src/image_loader.cpp +++ b/others/C++/Image_format_converter/src/image_loader.cpp @@ -3,11 +3,25 @@ #include #include #include +#include #include #include #include #include + + +static bool is_avif_file(const std::string& path) { + std::ifstream file(path, std::ios::binary); + if (!file) return false; + + char header[12]; + if (!file.read(header, 12)) return false; + + return !memcmp(header, "\0\0\0 ftypavif", 12) || + !memcmp(header, "\0\0\0 ftypavis", 12); +} + static bool is_webp_file(const std::string& path) { std::ifstream file(path, std::ios::binary); if (!file) return false; @@ -18,11 +32,74 @@ static bool is_webp_file(const std::string& path) { return !memcmp(header, "RIFF", 4) && !memcmp(header + 8, "WEBP", 4); } +static ImageData load_avif(const std::string& path) { + ImageData data; + + avifDecoder* decoder = avifDecoderCreate(); + if (!decoder) { + throw std::runtime_error("无法创建AVIF解码器"); + } + + avifResult result = avifDecoderSetIOFile(decoder, path.c_str()); + if (result != AVIF_RESULT_OK) { + avifDecoderDestroy(decoder); + throw std::runtime_error("无法读取AVIF文件"); + } + + result = avifDecoderParse(decoder); + if (result != AVIF_RESULT_OK) { + avifDecoderDestroy(decoder); + throw std::runtime_error("无效的AVIF图像"); + } + + result = avifDecoderNextImage(decoder); + if (result != AVIF_RESULT_OK) { + avifDecoderDestroy(decoder); + throw std::runtime_error("无法解码AVIF图像"); + } + + data.width = decoder->image->width; + data.height = decoder->image->height; + data.channels = 4; // AVIF解码为RGBA + + // 分配内存并转换图像数据 + uint8_t* rgba_pixels = new uint8_t[data.width * data.height * 4]; + avifRGBImage rgb; + avifRGBImageSetDefaults(&rgb, decoder->image); + rgb.format = AVIF_RGB_FORMAT_RGBA; + rgb.depth = 8; + rgb.pixels = rgba_pixels; + rgb.rowBytes = data.width * 4; + + if (avifImageYUVToRGB(decoder->image, &rgb) != AVIF_RESULT_OK) { + delete[] rgba_pixels; + avifDecoderDestroy(decoder); + throw std::runtime_error("AVIF颜色空间转换失败"); + } + + avifDecoderDestroy(decoder); + + // 验证图像数据 + try { + ImageLoader::validate_image(rgba_pixels, data.width, data.height); + } catch (...) { + delete[] rgba_pixels; + throw; + } + + data.pixels = std::unique_ptr(rgba_pixels, [](void* p) { delete[] static_cast(p); }); + return data; +} + ImageData ImageLoader::load(const std::string& path) { ImageData data; + // 检查是否为AVIF格式 + if (is_avif_file(path)) { + return load_avif(path); + } // 检查是否为WebP格式 - if (is_webp_file(path)) { + else if (is_webp_file(path)) { // 读取WebP文件数据 std::ifstream file(path, std::ios::binary | std::ios::ate); if (!file) { @@ -65,7 +142,7 @@ ImageData ImageLoader::load(const std::string& path) { // 验证图像数据 try { - validate_image(rgb_pixels, data.width, data.height); + ImageLoader::validate_image(rgb_pixels, data.width, data.height); } catch (...) { delete[] rgb_pixels; throw; @@ -75,7 +152,7 @@ ImageData ImageLoader::load(const std::string& path) { } else { // 验证图像数据 try { - validate_image(rgba_pixels, data.width, data.height); + ImageLoader::validate_image(rgba_pixels, data.width, data.height); } catch (...) { WebPFree(rgba_pixels); throw; @@ -96,7 +173,7 @@ ImageData ImageLoader::load(const std::string& path) { // 验证图像数据 try { - validate_image(pixels, data.width, data.height); + ImageLoader::validate_image(pixels, data.width, data.height); } catch (...) { stbi_image_free(pixels); throw; diff --git a/others/C++/Image_format_converter/src/jpeg_to_avif.cpp b/others/C++/Image_format_converter/src/jpeg_to_avif.cpp new file mode 100644 index 0000000..507ff84 --- /dev/null +++ b/others/C++/Image_format_converter/src/jpeg_to_avif.cpp @@ -0,0 +1,71 @@ +#include "jpeg_to_avif.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool JpegToAvifConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载JPEG图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 创建AVIF编码器 + avifEncoder* encoder = avifEncoderCreate(); + encoder->maxThreads = 4; + encoder->minQuantizer = 20; + encoder->maxQuantizer = 20; + encoder->speed = 6; + + // 创建AVIF图像 + avifImage* image = avifImageCreate(data.width, data.height, 8, AVIF_PIXEL_FORMAT_YUV420); + avifRGBImage rgbImage; + avifRGBImageSetDefaults(&rgbImage, image); + rgbImage.pixels = data.pixels.get(); + rgbImage.rowBytes = data.width * data.channels; + rgbImage.format = (data.channels == 3) ? AVIF_RGB_FORMAT_RGB : AVIF_RGB_FORMAT_RGBA; + + // 转换RGB到YUV + if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 编码AVIF图像 + avifRWData output = AVIF_DATA_EMPTY; + if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 保存AVIF文件 + FILE* f = fopen(output_path.c_str(), "wb"); + if (!f) { + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + fwrite(output.data, 1, output.size, f); + fclose(f); + + // 清理资源 + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return true; +} + +bool JpegToAvifConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/jpg_to_avif.cpp b/others/C++/Image_format_converter/src/jpg_to_avif.cpp new file mode 100644 index 0000000..1b27e7a --- /dev/null +++ b/others/C++/Image_format_converter/src/jpg_to_avif.cpp @@ -0,0 +1,71 @@ +#include "jpg_to_avif.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool JpgToAvifConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载JPG图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 创建AVIF编码器 + avifEncoder* encoder = avifEncoderCreate(); + encoder->maxThreads = 4; + encoder->minQuantizer = 20; + encoder->maxQuantizer = 20; + encoder->speed = 6; + + // 创建AVIF图像 + avifImage* image = avifImageCreate(data.width, data.height, 8, AVIF_PIXEL_FORMAT_YUV420); + avifRGBImage rgbImage; + avifRGBImageSetDefaults(&rgbImage, image); + rgbImage.pixels = data.pixels.get(); + rgbImage.rowBytes = data.width * data.channels; + rgbImage.format = (data.channels == 3) ? AVIF_RGB_FORMAT_RGB : AVIF_RGB_FORMAT_RGBA; + + // 转换RGB到YUV + if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 编码AVIF图像 + avifRWData output = AVIF_DATA_EMPTY; + if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 保存AVIF文件 + FILE* f = fopen(output_path.c_str(), "wb"); + if (!f) { + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + fwrite(output.data, 1, output.size, f); + fclose(f); + + // 清理资源 + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return true; +} + +bool JpgToAvifConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/png_to_avif.cpp b/others/C++/Image_format_converter/src/png_to_avif.cpp new file mode 100644 index 0000000..313ba96 --- /dev/null +++ b/others/C++/Image_format_converter/src/png_to_avif.cpp @@ -0,0 +1,71 @@ +#include "png_to_avif.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool PngToAvifConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载PNG图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 创建AVIF编码器 + avifEncoder* encoder = avifEncoderCreate(); + encoder->maxThreads = 4; + encoder->minQuantizer = 20; + encoder->maxQuantizer = 20; + encoder->speed = 6; + + // 创建AVIF图像 + avifImage* image = avifImageCreate(data.width, data.height, 8, AVIF_PIXEL_FORMAT_YUV420); + avifRGBImage rgbImage; + avifRGBImageSetDefaults(&rgbImage, image); + rgbImage.pixels = data.pixels.get(); + rgbImage.rowBytes = data.width * data.channels; + rgbImage.format = (data.channels == 3) ? AVIF_RGB_FORMAT_RGB : AVIF_RGB_FORMAT_RGBA; + + // 转换RGB到YUV + if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 编码AVIF图像 + avifRWData output = AVIF_DATA_EMPTY; + if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 保存AVIF文件 + FILE* f = fopen(output_path.c_str(), "wb"); + if (!f) { + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + fwrite(output.data, 1, output.size, f); + fclose(f); + + // 清理资源 + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return true; +} + +bool PngToAvifConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/stb_impl.cpp b/others/C++/Image_format_converter/src/stb_impl.cpp index c4e57f6..9e48c7c 100644 --- a/others/C++/Image_format_converter/src/stb_impl.cpp +++ b/others/C++/Image_format_converter/src/stb_impl.cpp @@ -1,4 +1,4 @@ -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_WRITE_IMPLEMENTATION -#include -#include +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include +#include diff --git a/others/C++/Image_format_converter/src/tiff_to_avif.cpp b/others/C++/Image_format_converter/src/tiff_to_avif.cpp new file mode 100644 index 0000000..476daae --- /dev/null +++ b/others/C++/Image_format_converter/src/tiff_to_avif.cpp @@ -0,0 +1,71 @@ +#include "tiff_to_avif.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool TiffToAvifConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载TIFF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 创建AVIF编码器 + avifEncoder* encoder = avifEncoderCreate(); + encoder->maxThreads = 4; + encoder->minQuantizer = 20; + encoder->maxQuantizer = 20; + encoder->speed = 6; + + // 创建AVIF图像 + avifImage* image = avifImageCreate(data.width, data.height, 8, AVIF_PIXEL_FORMAT_YUV420); + avifRGBImage rgbImage; + avifRGBImageSetDefaults(&rgbImage, image); + rgbImage.pixels = data.pixels.get(); + rgbImage.rowBytes = data.width * data.channels; + rgbImage.format = (data.channels == 3) ? AVIF_RGB_FORMAT_RGB : AVIF_RGB_FORMAT_RGBA; + + // 转换RGB到YUV + if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 编码AVIF图像 + avifRWData output = AVIF_DATA_EMPTY; + if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 保存AVIF文件 + FILE* f = fopen(output_path.c_str(), "wb"); + if (!f) { + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + fwrite(output.data, 1, output.size, f); + fclose(f); + + // 清理资源 + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return true; +} + +bool TiffToAvifConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 1 || data.channels == 3 || data.channels == 4); +} diff --git a/others/C++/Image_format_converter/src/webp_to_avif.cpp b/others/C++/Image_format_converter/src/webp_to_avif.cpp new file mode 100644 index 0000000..44ad90b --- /dev/null +++ b/others/C++/Image_format_converter/src/webp_to_avif.cpp @@ -0,0 +1,71 @@ +#include "webp_to_avif.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool WebpToAvifConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 加载WEBP图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate(data)) { + return false; + } + + // 创建AVIF编码器 + avifEncoder* encoder = avifEncoderCreate(); + encoder->maxThreads = 4; + encoder->minQuantizer = 20; + encoder->maxQuantizer = 20; + encoder->speed = 6; + + // 创建AVIF图像 + avifImage* image = avifImageCreate(data.width, data.height, 8, AVIF_PIXEL_FORMAT_YUV420); + avifRGBImage rgbImage; + avifRGBImageSetDefaults(&rgbImage, image); + rgbImage.pixels = data.pixels.get(); + rgbImage.rowBytes = data.width * data.channels; + rgbImage.format = (data.channels == 3) ? AVIF_RGB_FORMAT_RGB : AVIF_RGB_FORMAT_RGBA; + + // 转换RGB到YUV + if (avifImageRGBToYUV(image, &rgbImage) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 编码AVIF图像 + avifRWData output = AVIF_DATA_EMPTY; + if (avifEncoderWrite(encoder, image, &output) != AVIF_RESULT_OK) { + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + + // 保存AVIF文件 + FILE* f = fopen(output_path.c_str(), "wb"); + if (!f) { + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return false; + } + fwrite(output.data, 1, output.size, f); + fclose(f); + + // 清理资源 + avifRWDataFree(&output); + avifEncoderDestroy(encoder); + avifImageDestroy(image); + return true; +} + +bool WebpToAvifConverter::validate(const ImageData& data) { + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +}