From d26ac95dd5a6e81e44ee6134ec4e1dbe4d07892a Mon Sep 17 00:00:00 2001 From: zsyg <3872006562@qq.com> Date: Thu, 10 Jul 2025 13:21:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E7=89=87=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E5=99=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- others/C++/Image_format_converter/Makefile | 25 ++++ .../include/bmp_to_jpg.hpp | 13 ++ .../include/bmp_to_png.hpp | 13 ++ .../include/bmp_to_tiff.hpp | 12 ++ .../Image_format_converter/include/common.hpp | 23 +++ .../include/converter_base.hpp | 13 ++ .../include/gui_interface.hpp | 23 +++ .../include/image_loader.hpp | 13 ++ .../include/jpg_to_bmp.hpp | 12 ++ .../include/jpg_to_png.hpp | 13 ++ .../include/jpg_to_tiff.hpp | 12 ++ .../include/png_to_bmp.hpp | 12 ++ .../include/png_to_jpg.hpp | 13 ++ .../include/png_to_tiff.hpp | 12 ++ .../include/tiff_to_bmp.hpp | 12 ++ .../include/tiff_to_jpg.hpp | 13 ++ .../include/tiff_to_png.hpp | 13 ++ .../Image_format_converter/src/bmp_to_jpg.cpp | 35 +++++ .../Image_format_converter/src/bmp_to_png.cpp | 35 +++++ .../src/bmp_to_tiff.cpp | 61 ++++++++ others/C++/Image_format_converter/src/gui.cpp | 137 ++++++++++++++++++ .../src/image_loader.cpp | 62 ++++++++ .../Image_format_converter/src/jpg_to_bmp.cpp | 33 +++++ .../Image_format_converter/src/jpg_to_png.cpp | 35 +++++ .../src/jpg_to_tiff.cpp | 61 ++++++++ .../C++/Image_format_converter/src/main.cpp | 8 + .../Image_format_converter/src/png_to_bmp.cpp | 33 +++++ .../Image_format_converter/src/png_to_jpg.cpp | 35 +++++ .../src/png_to_tiff.cpp | 61 ++++++++ .../Image_format_converter/src/stb_impl.cpp | 4 + .../src/tiff_to_bmp.cpp | 72 +++++++++ .../src/tiff_to_jpg.cpp | 73 ++++++++++ .../src/tiff_to_png.cpp | 73 ++++++++++ .../C++/Image_format_converter/src/utils.cpp | 11 ++ 34 files changed, 1076 insertions(+) create mode 100644 others/C++/Image_format_converter/Makefile create mode 100644 others/C++/Image_format_converter/include/bmp_to_jpg.hpp create mode 100644 others/C++/Image_format_converter/include/bmp_to_png.hpp create mode 100644 others/C++/Image_format_converter/include/bmp_to_tiff.hpp create mode 100644 others/C++/Image_format_converter/include/common.hpp create mode 100644 others/C++/Image_format_converter/include/converter_base.hpp create mode 100644 others/C++/Image_format_converter/include/gui_interface.hpp create mode 100644 others/C++/Image_format_converter/include/image_loader.hpp create mode 100644 others/C++/Image_format_converter/include/jpg_to_bmp.hpp create mode 100644 others/C++/Image_format_converter/include/jpg_to_png.hpp create mode 100644 others/C++/Image_format_converter/include/jpg_to_tiff.hpp create mode 100644 others/C++/Image_format_converter/include/png_to_bmp.hpp create mode 100644 others/C++/Image_format_converter/include/png_to_jpg.hpp create mode 100644 others/C++/Image_format_converter/include/png_to_tiff.hpp create mode 100644 others/C++/Image_format_converter/include/tiff_to_bmp.hpp create mode 100644 others/C++/Image_format_converter/include/tiff_to_jpg.hpp create mode 100644 others/C++/Image_format_converter/include/tiff_to_png.hpp create mode 100644 others/C++/Image_format_converter/src/bmp_to_jpg.cpp create mode 100644 others/C++/Image_format_converter/src/bmp_to_png.cpp create mode 100644 others/C++/Image_format_converter/src/bmp_to_tiff.cpp create mode 100644 others/C++/Image_format_converter/src/gui.cpp create mode 100644 others/C++/Image_format_converter/src/image_loader.cpp create mode 100644 others/C++/Image_format_converter/src/jpg_to_bmp.cpp create mode 100644 others/C++/Image_format_converter/src/jpg_to_png.cpp create mode 100644 others/C++/Image_format_converter/src/jpg_to_tiff.cpp create mode 100644 others/C++/Image_format_converter/src/main.cpp create mode 100644 others/C++/Image_format_converter/src/png_to_bmp.cpp create mode 100644 others/C++/Image_format_converter/src/png_to_jpg.cpp create mode 100644 others/C++/Image_format_converter/src/png_to_tiff.cpp create mode 100644 others/C++/Image_format_converter/src/stb_impl.cpp create mode 100644 others/C++/Image_format_converter/src/tiff_to_bmp.cpp create mode 100644 others/C++/Image_format_converter/src/tiff_to_jpg.cpp create mode 100644 others/C++/Image_format_converter/src/tiff_to_png.cpp create mode 100644 others/C++/Image_format_converter/src/utils.cpp diff --git a/others/C++/Image_format_converter/Makefile b/others/C++/Image_format_converter/Makefile new file mode 100644 index 0000000..75a2fc6 --- /dev/null +++ b/others/C++/Image_format_converter/Makefile @@ -0,0 +1,25 @@ +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 +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/bmp_to_jpg.hpp b/others/C++/Image_format_converter/include/bmp_to_jpg.hpp new file mode 100644 index 0000000..cb91cd0 --- /dev/null +++ b/others/C++/Image_format_converter/include/bmp_to_jpg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class BmpToJpgConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path, + int quality = 90); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/bmp_to_png.hpp b/others/C++/Image_format_converter/include/bmp_to_png.hpp new file mode 100644 index 0000000..b809044 --- /dev/null +++ b/others/C++/Image_format_converter/include/bmp_to_png.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class BmpToPngConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path, + int compression_level = 6); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/bmp_to_tiff.hpp b/others/C++/Image_format_converter/include/bmp_to_tiff.hpp new file mode 100644 index 0000000..a222c66 --- /dev/null +++ b/others/C++/Image_format_converter/include/bmp_to_tiff.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class BmpToTiffConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/common.hpp b/others/C++/Image_format_converter/include/common.hpp new file mode 100644 index 0000000..af6fa96 --- /dev/null +++ b/others/C++/Image_format_converter/include/common.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include +#include + +struct ImageData { + int width; + int height; + int channels; + std::unique_ptr pixels; + + ImageData() : pixels(nullptr, stbi_image_free) {} +}; + +enum class ImageFormat { + PNG, + JPG, + TIFF, + UNKNOWN +}; + +ImageFormat get_format_from_extension(const std::string& path); diff --git a/others/C++/Image_format_converter/include/converter_base.hpp b/others/C++/Image_format_converter/include/converter_base.hpp new file mode 100644 index 0000000..dbf658d --- /dev/null +++ b/others/C++/Image_format_converter/include/converter_base.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class ConverterBase { +public: + virtual ~ConverterBase() = default; + virtual bool convert(const std::string& input, + const std::string& output) = 0; + +protected: + virtual bool validate(const ImageData& data) = 0; +}; diff --git a/others/C++/Image_format_converter/include/gui_interface.hpp b/others/C++/Image_format_converter/include/gui_interface.hpp new file mode 100644 index 0000000..1161e8a --- /dev/null +++ b/others/C++/Image_format_converter/include/gui_interface.hpp @@ -0,0 +1,23 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +class MainWindow : public Fl_Window { +public: + MainWindow(int w, int h, const char* title); + +private: + Fl_Input* input_path; + Fl_Output* output_path; + Fl_Choice* format_choice; + Fl_Button* convert_btn; + + static void input_file_cb(Fl_Widget* w, void* data); + static void output_file_cb(Fl_Widget* w, void* data); + static void convert_cb(Fl_Widget* w, void* data); +}; diff --git a/others/C++/Image_format_converter/include/image_loader.hpp b/others/C++/Image_format_converter/include/image_loader.hpp new file mode 100644 index 0000000..cf2fce8 --- /dev/null +++ b/others/C++/Image_format_converter/include/image_loader.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "common.hpp" +#include + +class ImageLoader { +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); + +private: + static void validate_image(const unsigned char* data, int width, int height); +}; diff --git a/others/C++/Image_format_converter/include/jpg_to_bmp.hpp b/others/C++/Image_format_converter/include/jpg_to_bmp.hpp new file mode 100644 index 0000000..a09092a --- /dev/null +++ b/others/C++/Image_format_converter/include/jpg_to_bmp.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class JpgToBmpConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/jpg_to_png.hpp b/others/C++/Image_format_converter/include/jpg_to_png.hpp new file mode 100644 index 0000000..75d3300 --- /dev/null +++ b/others/C++/Image_format_converter/include/jpg_to_png.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class JpgToPngConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path, + int compression_level = 6); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/jpg_to_tiff.hpp b/others/C++/Image_format_converter/include/jpg_to_tiff.hpp new file mode 100644 index 0000000..b191250 --- /dev/null +++ b/others/C++/Image_format_converter/include/jpg_to_tiff.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class JpgToTiffConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/png_to_bmp.hpp b/others/C++/Image_format_converter/include/png_to_bmp.hpp new file mode 100644 index 0000000..7b22acc --- /dev/null +++ b/others/C++/Image_format_converter/include/png_to_bmp.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class PngToBmpConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/png_to_jpg.hpp b/others/C++/Image_format_converter/include/png_to_jpg.hpp new file mode 100644 index 0000000..820de1e --- /dev/null +++ b/others/C++/Image_format_converter/include/png_to_jpg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class PngToJpgConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path, + int quality = 90); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/png_to_tiff.hpp b/others/C++/Image_format_converter/include/png_to_tiff.hpp new file mode 100644 index 0000000..0805e73 --- /dev/null +++ b/others/C++/Image_format_converter/include/png_to_tiff.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class PngToTiffConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/tiff_to_bmp.hpp b/others/C++/Image_format_converter/include/tiff_to_bmp.hpp new file mode 100644 index 0000000..74429d8 --- /dev/null +++ b/others/C++/Image_format_converter/include/tiff_to_bmp.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class TiffToBmpConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/tiff_to_jpg.hpp b/others/C++/Image_format_converter/include/tiff_to_jpg.hpp new file mode 100644 index 0000000..584b2b5 --- /dev/null +++ b/others/C++/Image_format_converter/include/tiff_to_jpg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class TiffToJpgConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path, + int quality = 90); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/include/tiff_to_png.hpp b/others/C++/Image_format_converter/include/tiff_to_png.hpp new file mode 100644 index 0000000..d63b604 --- /dev/null +++ b/others/C++/Image_format_converter/include/tiff_to_png.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class TiffToPngConverter { +public: + static bool convert(const std::string& input_path, + const std::string& output_path, + int compression_level = 6); + +private: + static bool validate_input(const ImageData& data); +}; diff --git a/others/C++/Image_format_converter/src/bmp_to_jpg.cpp b/others/C++/Image_format_converter/src/bmp_to_jpg.cpp new file mode 100644 index 0000000..57e5573 --- /dev/null +++ b/others/C++/Image_format_converter/src/bmp_to_jpg.cpp @@ -0,0 +1,35 @@ +#include "bmp_to_jpg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool BmpToJpgConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 加载BMP图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(data)) { + return false; + } + + // 保存为JPG + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +bool BmpToJpgConverter::validate_input(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_png.cpp b/others/C++/Image_format_converter/src/bmp_to_png.cpp new file mode 100644 index 0000000..18edfc5 --- /dev/null +++ b/others/C++/Image_format_converter/src/bmp_to_png.cpp @@ -0,0 +1,35 @@ +#include "bmp_to_png.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool BmpToPngConverter::convert(const std::string& input_path, + const std::string& output_path, + int compression_level) { + // 加载BMP图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(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 BmpToPngConverter::validate_input(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/bmp_to_tiff.cpp b/others/C++/Image_format_converter/src/bmp_to_tiff.cpp new file mode 100644 index 0000000..8f53df0 --- /dev/null +++ b/others/C++/Image_format_converter/src/bmp_to_tiff.cpp @@ -0,0 +1,61 @@ +#include "bmp_to_tiff.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool BmpToTiffConverter::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_input(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); + + // 根据通道数设置PhotometricInterpretation + if (data.channels == 1) { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + } else if (data.channels == 3 || data.channels == 4) { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + } else { + TIFFClose(tif); + return false; + } + + // 写入图像数据 + tsize_t linebytes = data.width * data.channels; + unsigned char* buf = (unsigned char*)_TIFFmalloc(linebytes); + for (int y = 0; y < data.height; y++) { + memcpy(buf, &data.pixels.get()[y * linebytes], linebytes); + TIFFWriteScanline(tif, buf, y, 0); + } + + _TIFFfree(buf); + TIFFClose(tif); + return true; +} + +bool BmpToTiffConverter::validate_input(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/gui.cpp b/others/C++/Image_format_converter/src/gui.cpp new file mode 100644 index 0000000..d29203d --- /dev/null +++ b/others/C++/Image_format_converter/src/gui.cpp @@ -0,0 +1,137 @@ +#include +#include "gui_interface.hpp" +#include "png_to_jpg.hpp" +#include "jpg_to_png.hpp" +#include "bmp_to_png.hpp" +#include "bmp_to_jpg.hpp" +#include "png_to_bmp.hpp" +#include "jpg_to_bmp.hpp" +#include "tiff_to_bmp.hpp" +#include "bmp_to_tiff.hpp" +#include "tiff_to_png.hpp" +#include "png_to_tiff.hpp" +#include "tiff_to_jpg.hpp" +#include "jpg_to_tiff.hpp" +#include +#include +#include + +static void init_locale() { + setlocale(LC_ALL, "chs"); +} + +MainWindow::MainWindow(int w, int h, const char* title) + : Fl_Window(w, h, "图像格式转换器") { + init_locale(); + + input_path = new Fl_Input(100, 20, 250, 25, "输入文件:"); + Fl_Button* input_btn = new Fl_Button(360, 20, 30, 25, "..."); + input_btn->callback(input_file_cb, this); + + output_path = new Fl_Output(100, 60, 250, 25, "输出文件:"); + Fl_Button* output_btn = new Fl_Button(360, 60, 30, 25, "..."); + output_btn->callback(output_file_cb, this); + + format_choice = new Fl_Choice(100, 100, 150, 25, "转换格式:"); + format_choice->add("PNG to JPG"); + format_choice->add("JPG to PNG"); + format_choice->add("BMP to PNG"); + format_choice->add("BMP to JPG"); + format_choice->add("PNG to BMP"); + format_choice->add("JPG to BMP"); + format_choice->add("TIFF to BMP"); + format_choice->add("BMP to TIFF"); + format_choice->add("TIFF to PNG"); + format_choice->add("PNG to TIFF"); + format_choice->add("TIFF to JPG"); + format_choice->add("JPG to TIFF"); + format_choice->value(0); + + convert_btn = new Fl_Button(150, 150, 100, 30, "转换"); + convert_btn->callback(convert_cb, this); + + end(); +} + +void MainWindow::input_file_cb(Fl_Widget* w, void* data) { + MainWindow* win = static_cast(data); + Fl_File_Chooser chooser(".", "*.*", Fl_File_Chooser::SINGLE, "选择输入文件"); + chooser.show(); + while(chooser.shown()) Fl::wait(); + if(chooser.value()) { + win->input_path->value(chooser.value()); + } +} + +void MainWindow::output_file_cb(Fl_Widget* w, void* data) { + MainWindow* win = static_cast(data); + Fl_File_Chooser chooser(".", "*.*", Fl_File_Chooser::CREATE, "选择输出文件"); + chooser.show(); + while(chooser.shown()) Fl::wait(); + if(chooser.value()) { + win->output_path->value(chooser.value()); + } +} + +void MainWindow::convert_cb(Fl_Widget* w, void* data) { + MainWindow* win = static_cast(data); + std::string input = win->input_path->value(); + std::string output = win->output_path->value(); + + if (input.empty() || output.empty()) { + fl_alert("请输入有效的文件路径!"); + return; + } + + bool success = false; + try { + switch(win->format_choice->value()) { + case 0: // PNG to JPG + success = PngToJpgConverter::convert(input, output); + break; + case 1: // JPG to PNG + success = JpgToPngConverter::convert(input, output); + break; + case 2: // BMP to PNG + success = BmpToPngConverter::convert(input, output); + break; + case 3: // BMP to JPG + success = BmpToJpgConverter::convert(input, output); + break; + case 4: // PNG to BMP + success = PngToBmpConverter::convert(input, output); + break; + case 5: // JPG to BMP + success = JpgToBmpConverter::convert(input, output); + break; + case 6: // TIFF to BMP + success = TiffToBmpConverter::convert(input, output); + break; + case 7: // BMP to TIFF + success = BmpToTiffConverter::convert(input, output); + break; + case 8: // TIFF to PNG + success = TiffToPngConverter::convert(input, output); + break; + case 9: // PNG to TIFF + success = PngToTiffConverter::convert(input, output); + break; + case 10: // TIFF to JPG + success = TiffToJpgConverter::convert(input, output); + break; + case 11: // JPG to TIFF + success = JpgToTiffConverter::convert(input, output); + break; + } + if (!success) throw std::runtime_error("转换失败"); + } catch (const std::exception& e) { + fl_alert("转换错误: %s", e.what()); + return; + } + + if (success) { + fl_message("转换成功!"); + } else { + fl_alert("转换失败,请检查输入文件!"); + } +} diff --git a/others/C++/Image_format_converter/src/image_loader.cpp b/others/C++/Image_format_converter/src/image_loader.cpp new file mode 100644 index 0000000..7e78aec --- /dev/null +++ b/others/C++/Image_format_converter/src/image_loader.cpp @@ -0,0 +1,62 @@ +#include "image_loader.hpp" +#include "common.hpp" +#include +#include +#include +#include + +ImageData ImageLoader::load(const std::string& path) { + ImageData data; + + // 加载图像 + unsigned char* pixels = stbi_load(path.c_str(), + &data.width, + &data.height, + &data.channels, + 0); + if (!pixels) { + throw std::runtime_error("无法加载图像: " + std::string(stbi_failure_reason())); + } + + // 验证图像数据 + try { + validate_image(pixels, data.width, data.height); + } catch (...) { + stbi_image_free(pixels); + throw; + } + + // 转移所有权到智能指针 + data.pixels.reset(pixels); + return data; +} + +bool ImageLoader::save_png(const std::string& path, const ImageData& data) { + if (!data.pixels || data.width <= 0 || data.height <= 0) { + return false; + } + return stbi_write_png(path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + data.width * data.channels); +} + +bool ImageLoader::save_jpg(const std::string& path, const ImageData& data, int quality) { + if (!data.pixels || data.width <= 0 || data.height <= 0) { + return false; + } + return stbi_write_jpg(path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +void ImageLoader::validate_image(const unsigned char* data, int width, int height) { + if (!data || width <= 0 || height <= 0) { + throw std::runtime_error("无效的图像数据"); + } +} diff --git a/others/C++/Image_format_converter/src/jpg_to_bmp.cpp b/others/C++/Image_format_converter/src/jpg_to_bmp.cpp new file mode 100644 index 0000000..276388e --- /dev/null +++ b/others/C++/Image_format_converter/src/jpg_to_bmp.cpp @@ -0,0 +1,33 @@ +#include "jpg_to_bmp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool JpgToBmpConverter::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_input(data)) { + return false; + } + + // 保存为BMP + return stbi_write_bmp(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get()); +} + +bool JpgToBmpConverter::validate_input(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/jpg_to_png.cpp b/others/C++/Image_format_converter/src/jpg_to_png.cpp new file mode 100644 index 0000000..96ed64f --- /dev/null +++ b/others/C++/Image_format_converter/src/jpg_to_png.cpp @@ -0,0 +1,35 @@ +#include "jpg_to_png.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool JpgToPngConverter::convert(const std::string& input_path, + const std::string& output_path, + int compression_level) { + // 加载JPG图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(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 JpgToPngConverter::validate_input(const ImageData& data) { + // 确保是有效的图像数据 + return data.width > 0 && data.height > 0 && + (data.channels == 1 || data.channels == 3); +} diff --git a/others/C++/Image_format_converter/src/jpg_to_tiff.cpp b/others/C++/Image_format_converter/src/jpg_to_tiff.cpp new file mode 100644 index 0000000..14a4017 --- /dev/null +++ b/others/C++/Image_format_converter/src/jpg_to_tiff.cpp @@ -0,0 +1,61 @@ +#include "jpg_to_tiff.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool JpgToTiffConverter::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_input(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); + + // 根据通道数设置PhotometricInterpretation + if (data.channels == 1) { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + } else if (data.channels == 3 || data.channels == 4) { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + } else { + TIFFClose(tif); + return false; + } + + // 写入图像数据 + tsize_t linebytes = data.width * data.channels; + unsigned char* buf = (unsigned char*)_TIFFmalloc(linebytes); + for (int y = 0; y < data.height; y++) { + memcpy(buf, &data.pixels.get()[y * linebytes], linebytes); + TIFFWriteScanline(tif, buf, y, 0); + } + + _TIFFfree(buf); + TIFFClose(tif); + return true; +} + +bool JpgToTiffConverter::validate_input(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/main.cpp b/others/C++/Image_format_converter/src/main.cpp new file mode 100644 index 0000000..e399376 --- /dev/null +++ b/others/C++/Image_format_converter/src/main.cpp @@ -0,0 +1,8 @@ +#include "gui_interface.hpp" +#include + +int main(int argc, char** argv) { + MainWindow window(400, 300, "Image Format Converter"); + window.show(argc, argv); + return Fl::run(); +} diff --git a/others/C++/Image_format_converter/src/png_to_bmp.cpp b/others/C++/Image_format_converter/src/png_to_bmp.cpp new file mode 100644 index 0000000..ba8e383 --- /dev/null +++ b/others/C++/Image_format_converter/src/png_to_bmp.cpp @@ -0,0 +1,33 @@ +#include "png_to_bmp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool PngToBmpConverter::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_input(data)) { + return false; + } + + // 保存为BMP + return stbi_write_bmp(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get()); +} + +bool PngToBmpConverter::validate_input(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/png_to_jpg.cpp b/others/C++/Image_format_converter/src/png_to_jpg.cpp new file mode 100644 index 0000000..3e771e2 --- /dev/null +++ b/others/C++/Image_format_converter/src/png_to_jpg.cpp @@ -0,0 +1,35 @@ +#include "png_to_jpg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool PngToJpgConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 加载PNG图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(data)) { + return false; + } + + // 保存为JPG + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +bool PngToJpgConverter::validate_input(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_tiff.cpp b/others/C++/Image_format_converter/src/png_to_tiff.cpp new file mode 100644 index 0000000..a165b35 --- /dev/null +++ b/others/C++/Image_format_converter/src/png_to_tiff.cpp @@ -0,0 +1,61 @@ +#include "png_to_tiff.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool PngToTiffConverter::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_input(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); + + // 根据通道数设置PhotometricInterpretation + if (data.channels == 1) { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + } else if (data.channels == 3 || data.channels == 4) { + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + } else { + TIFFClose(tif); + return false; + } + + // 写入图像数据 + tsize_t linebytes = data.width * data.channels; + unsigned char* buf = (unsigned char*)_TIFFmalloc(linebytes); + for (int y = 0; y < data.height; y++) { + memcpy(buf, &data.pixels.get()[y * linebytes], linebytes); + TIFFWriteScanline(tif, buf, y, 0); + } + + _TIFFfree(buf); + TIFFClose(tif); + return true; +} + +bool PngToTiffConverter::validate_input(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/stb_impl.cpp b/others/C++/Image_format_converter/src/stb_impl.cpp new file mode 100644 index 0000000..c4e57f6 --- /dev/null +++ b/others/C++/Image_format_converter/src/stb_impl.cpp @@ -0,0 +1,4 @@ +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include +#include diff --git a/others/C++/Image_format_converter/src/tiff_to_bmp.cpp b/others/C++/Image_format_converter/src/tiff_to_bmp.cpp new file mode 100644 index 0000000..23d5564 --- /dev/null +++ b/others/C++/Image_format_converter/src/tiff_to_bmp.cpp @@ -0,0 +1,72 @@ +#include "tiff_to_bmp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool TiffToBmpConverter::convert(const std::string& input_path, + const std::string& output_path) { + // 使用libtiff加载TIFF图像 + TIFF* tif = TIFFOpen(input_path.c_str(), "r"); + if (!tif) { + return false; + } + + // 获取图像信息 + uint32 width, height; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + + // 获取TIFF格式信息 + uint16 samplesperpixel, bitspersample, photometric; + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric); + + // 验证TIFF格式 + if (bitspersample != 8) { + TIFFClose(tif); + return false; + } + + // 设置输出通道数 + ImageData data; + data.width = width; + data.height = height; + data.channels = samplesperpixel; + data.pixels.reset(new unsigned char[width * height * data.channels]); + + // 读取图像数据 + tdata_t buf = _TIFFmalloc(TIFFScanlineSize(tif)); + for (uint32 row = 0; row < height; row++) { + if (TIFFReadScanline(tif, buf, row) == -1) { + _TIFFfree(buf); + TIFFClose(tif); + return false; + } + memcpy(&data.pixels.get()[row * width * data.channels], + buf, + width * data.channels); + } + + _TIFFfree(buf); + TIFFClose(tif); + + // 验证输入 + if (!validate_input(data)) { + return false; + } + + // 保存为BMP + return stbi_write_bmp(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get()); +} + +bool TiffToBmpConverter::validate_input(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/tiff_to_jpg.cpp b/others/C++/Image_format_converter/src/tiff_to_jpg.cpp new file mode 100644 index 0000000..96e60d2 --- /dev/null +++ b/others/C++/Image_format_converter/src/tiff_to_jpg.cpp @@ -0,0 +1,73 @@ +#include "tiff_to_jpg.hpp" +#include "common.hpp" +#include +#include +#include + +bool TiffToJpgConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 使用libtiff加载TIFF图像 + TIFF* tif = TIFFOpen(input_path.c_str(), "r"); + if (!tif) { + return false; + } + + // 获取图像信息 + uint32 width, height; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + + // 获取TIFF格式信息 + uint16 samplesperpixel, bitspersample, photometric; + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric); + + // 验证TIFF格式 + if (bitspersample != 8) { + TIFFClose(tif); + return false; + } + + // 设置输出通道数 + ImageData data; + data.width = width; + data.height = height; + data.channels = samplesperpixel; + data.pixels.reset(new unsigned char[width * height * data.channels]); + + // 读取图像数据 + tdata_t buf = _TIFFmalloc(TIFFScanlineSize(tif)); + for (uint32 row = 0; row < height; row++) { + if (TIFFReadScanline(tif, buf, row) == -1) { + _TIFFfree(buf); + TIFFClose(tif); + return false; + } + memcpy(&data.pixels.get()[row * width * data.channels], + buf, + width * data.channels); + } + + _TIFFfree(buf); + TIFFClose(tif); + + // 验证输入 + if (!validate_input(data)) { + return false; + } + + // 保存为JPG + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +bool TiffToJpgConverter::validate_input(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/tiff_to_png.cpp b/others/C++/Image_format_converter/src/tiff_to_png.cpp new file mode 100644 index 0000000..fd425ac --- /dev/null +++ b/others/C++/Image_format_converter/src/tiff_to_png.cpp @@ -0,0 +1,73 @@ +#include "tiff_to_png.hpp" +#include "common.hpp" +#include +#include +#include + +bool TiffToPngConverter::convert(const std::string& input_path, + const std::string& output_path, + int compression_level) { + // 使用libtiff加载TIFF图像 + TIFF* tif = TIFFOpen(input_path.c_str(), "r"); + if (!tif) { + return false; + } + + // 获取图像信息 + uint32 width, height; + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + + // 获取TIFF格式信息 + uint16 samplesperpixel, bitspersample, photometric; + TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); + TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); + TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric); + + // 验证TIFF格式 + if (bitspersample != 8) { + TIFFClose(tif); + return false; + } + + // 设置输出通道数 + ImageData data; + data.width = width; + data.height = height; + data.channels = samplesperpixel; + data.pixels.reset(new unsigned char[width * height * data.channels]); + + // 读取图像数据 + tdata_t buf = _TIFFmalloc(TIFFScanlineSize(tif)); + for (uint32 row = 0; row < height; row++) { + if (TIFFReadScanline(tif, buf, row) == -1) { + _TIFFfree(buf); + TIFFClose(tif); + return false; + } + memcpy(&data.pixels.get()[row * width * data.channels], + buf, + width * data.channels); + } + + _TIFFfree(buf); + TIFFClose(tif); + + // 验证输入 + if (!validate_input(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 TiffToPngConverter::validate_input(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/utils.cpp b/others/C++/Image_format_converter/src/utils.cpp new file mode 100644 index 0000000..b3d8398 --- /dev/null +++ b/others/C++/Image_format_converter/src/utils.cpp @@ -0,0 +1,11 @@ +#include "common.hpp" +#include + +ImageFormat get_format_from_extension(const std::string& path) { + std::string ext = path.substr(path.find_last_of(".") + 1); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + + if (ext == "png") return ImageFormat::PNG; + if (ext == "jpg" || ext == "jpeg") return ImageFormat::JPG; + return ImageFormat::UNKNOWN; +}