diff --git a/others/C++/Image_format_converter/Makefile b/others/C++/Image_format_converter/Makefile index 75a2fc6..98b18b0 100644 --- a/others/C++/Image_format_converter/Makefile +++ b/others/C++/Image_format_converter/Makefile @@ -7,7 +7,12 @@ SRC = src/main.cpp src/gui.cpp src/utils.cpp src/stb_impl.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/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 diff --git a/others/C++/Image_format_converter/include/bmp_to_jpeg.hpp b/others/C++/Image_format_converter/include/bmp_to_jpeg.hpp new file mode 100644 index 0000000..035fc6b --- /dev/null +++ b/others/C++/Image_format_converter/include/bmp_to_jpeg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class BmpToJpegConverter { +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_webp.hpp b/others/C++/Image_format_converter/include/bmp_to_webp.hpp new file mode 100644 index 0000000..b270348 --- /dev/null +++ b/others/C++/Image_format_converter/include/bmp_to_webp.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class BmpToWebpConverter { +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/common.hpp b/others/C++/Image_format_converter/include/common.hpp index af6fa96..50bc33b 100644 --- a/others/C++/Image_format_converter/include/common.hpp +++ b/others/C++/Image_format_converter/include/common.hpp @@ -17,6 +17,7 @@ enum class ImageFormat { PNG, JPG, TIFF, + WEBP, UNKNOWN }; diff --git a/others/C++/Image_format_converter/include/jpeg_to_bmp.hpp b/others/C++/Image_format_converter/include/jpeg_to_bmp.hpp new file mode 100644 index 0000000..8ff003d --- /dev/null +++ b/others/C++/Image_format_converter/include/jpeg_to_bmp.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class JpegToBmpConverter { +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/jpeg_to_png.hpp b/others/C++/Image_format_converter/include/jpeg_to_png.hpp new file mode 100644 index 0000000..dbc32f7 --- /dev/null +++ b/others/C++/Image_format_converter/include/jpeg_to_png.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class JpegToPngConverter { +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/jpeg_to_tiff.hpp b/others/C++/Image_format_converter/include/jpeg_to_tiff.hpp new file mode 100644 index 0000000..f6ed82e --- /dev/null +++ b/others/C++/Image_format_converter/include/jpeg_to_tiff.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class JpegToTiffConverter { +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/jpeg_to_webp.hpp b/others/C++/Image_format_converter/include/jpeg_to_webp.hpp new file mode 100644 index 0000000..2ca7b69 --- /dev/null +++ b/others/C++/Image_format_converter/include/jpeg_to_webp.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class JpegToWebpConverter { +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/jpg_to_webp.hpp b/others/C++/Image_format_converter/include/jpg_to_webp.hpp new file mode 100644 index 0000000..7f68e61 --- /dev/null +++ b/others/C++/Image_format_converter/include/jpg_to_webp.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class JpgToWebpConverter { +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_jpeg.hpp b/others/C++/Image_format_converter/include/png_to_jpeg.hpp new file mode 100644 index 0000000..652ccfb --- /dev/null +++ b/others/C++/Image_format_converter/include/png_to_jpeg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class PngToJpegConverter { +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_webp.hpp b/others/C++/Image_format_converter/include/png_to_webp.hpp new file mode 100644 index 0000000..f0e213d --- /dev/null +++ b/others/C++/Image_format_converter/include/png_to_webp.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class PngToWebpConverter { +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_jpeg.hpp b/others/C++/Image_format_converter/include/tiff_to_jpeg.hpp new file mode 100644 index 0000000..8ceb73f --- /dev/null +++ b/others/C++/Image_format_converter/include/tiff_to_jpeg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class TiffToJpegConverter { +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_webp.hpp b/others/C++/Image_format_converter/include/tiff_to_webp.hpp new file mode 100644 index 0000000..37a2f00 --- /dev/null +++ b/others/C++/Image_format_converter/include/tiff_to_webp.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class TiffToWebpConverter { +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/webp_to_bmp.hpp b/others/C++/Image_format_converter/include/webp_to_bmp.hpp new file mode 100644 index 0000000..40c0f90 --- /dev/null +++ b/others/C++/Image_format_converter/include/webp_to_bmp.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class WebpToBmpConverter { +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/webp_to_jpeg.hpp b/others/C++/Image_format_converter/include/webp_to_jpeg.hpp new file mode 100644 index 0000000..5314f3f --- /dev/null +++ b/others/C++/Image_format_converter/include/webp_to_jpeg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class WebpToJpegConverter { +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/webp_to_jpg.hpp b/others/C++/Image_format_converter/include/webp_to_jpg.hpp new file mode 100644 index 0000000..31264a5 --- /dev/null +++ b/others/C++/Image_format_converter/include/webp_to_jpg.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include "common.hpp" + +class WebpToJpgConverter { +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/webp_to_png.hpp b/others/C++/Image_format_converter/include/webp_to_png.hpp new file mode 100644 index 0000000..f504d26 --- /dev/null +++ b/others/C++/Image_format_converter/include/webp_to_png.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class WebpToPngConverter { +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/webp_to_tiff.hpp b/others/C++/Image_format_converter/include/webp_to_tiff.hpp new file mode 100644 index 0000000..df46931 --- /dev/null +++ b/others/C++/Image_format_converter/include/webp_to_tiff.hpp @@ -0,0 +1,12 @@ +#pragma once +#include +#include "common.hpp" + +class WebpToTiffConverter { +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/src/bmp_to_jpeg.cpp b/others/C++/Image_format_converter/src/bmp_to_jpeg.cpp new file mode 100644 index 0000000..f35251d --- /dev/null +++ b/others/C++/Image_format_converter/src/bmp_to_jpeg.cpp @@ -0,0 +1,35 @@ +#include "bmp_to_jpeg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool BmpToJpegConverter::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; + } + + // 保存为JPEG + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +bool BmpToJpegConverter::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_webp.cpp b/others/C++/Image_format_converter/src/bmp_to_webp.cpp new file mode 100644 index 0000000..f513470 --- /dev/null +++ b/others/C++/Image_format_converter/src/bmp_to_webp.cpp @@ -0,0 +1,61 @@ +#include "bmp_to_webp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool BmpToWebpConverter::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; + } + + // 编码为WebP + uint8_t* output = nullptr; + size_t output_size; + if (data.channels == 3) { + output_size = WebPEncodeRGB(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } else { + output_size = WebPEncodeRGBA(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } + + if (output_size == 0) { + return false; + } + + // 保存WebP文件 + FILE* file = fopen(output_path.c_str(), "wb"); + if (!file) { + WebPFree(output); + return false; + } + + fwrite(output, 1, output_size, file); + fclose(file); + WebPFree(output); + return true; +} + +bool BmpToWebpConverter::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/gui.cpp b/others/C++/Image_format_converter/src/gui.cpp index d29203d..bcb6b2d 100644 --- a/others/C++/Image_format_converter/src/gui.cpp +++ b/others/C++/Image_format_converter/src/gui.cpp @@ -12,6 +12,22 @@ #include "png_to_tiff.hpp" #include "tiff_to_jpg.hpp" #include "jpg_to_tiff.hpp" +#include "webp_to_jpg.hpp" +#include "webp_to_png.hpp" +#include "webp_to_bmp.hpp" +#include "webp_to_tiff.hpp" +#include "jpg_to_webp.hpp" +#include "png_to_webp.hpp" +#include "bmp_to_webp.hpp" +#include "tiff_to_webp.hpp" +#include "jpeg_to_png.hpp" +#include "jpeg_to_bmp.hpp" +#include "jpeg_to_tiff.hpp" +#include "jpeg_to_webp.hpp" +#include "png_to_jpeg.hpp" +#include "bmp_to_jpeg.hpp" +#include "tiff_to_jpeg.hpp" +#include "webp_to_jpeg.hpp" #include #include #include @@ -45,6 +61,22 @@ MainWindow::MainWindow(int w, int h, const char* title) format_choice->add("PNG to TIFF"); format_choice->add("TIFF to JPG"); format_choice->add("JPG to TIFF"); + format_choice->add("WEBP to JPG"); + format_choice->add("WEBP to PNG"); + format_choice->add("WEBP to BMP"); + format_choice->add("WEBP to TIFF"); + format_choice->add("JPG to WEBP"); + format_choice->add("PNG to WEBP"); + format_choice->add("BMP to WEBP"); + format_choice->add("TIFF to WEBP"); + format_choice->add("JPEG to PNG"); + format_choice->add("JPEG to BMP"); + format_choice->add("JPEG to TIFF"); + format_choice->add("JPEG to WEBP"); + format_choice->add("PNG to JPEG"); + format_choice->add("BMP to JPEG"); + format_choice->add("TIFF to JPEG"); + format_choice->add("WEBP to JPEG"); format_choice->value(0); convert_btn = new Fl_Button(150, 150, 100, 30, "转换"); @@ -122,6 +154,54 @@ void MainWindow::convert_cb(Fl_Widget* w, void* data) { case 11: // JPG to TIFF success = JpgToTiffConverter::convert(input, output); break; + case 12: // WEBP to JPG + success = WebpToJpgConverter::convert(input, output); + break; + case 13: // WEBP to PNG + success = WebpToPngConverter::convert(input, output); + break; + case 14: // WEBP to BMP + success = WebpToBmpConverter::convert(input, output); + break; + case 15: // WEBP to TIFF + success = WebpToTiffConverter::convert(input, output); + break; + case 16: // JPG to WEBP + success = JpgToWebpConverter::convert(input, output); + break; + case 17: // PNG to WEBP + success = PngToWebpConverter::convert(input, output); + break; + case 18: // BMP to WEBP + success = BmpToWebpConverter::convert(input, output); + break; + case 19: // TIFF to WEBP + success = TiffToWebpConverter::convert(input, output); + break; + case 20: // JPEG to PNG + success = JpegToPngConverter::convert(input, output); + break; + case 21: // JPEG to BMP + success = JpegToBmpConverter::convert(input, output); + break; + case 22: // JPEG to TIFF + success = JpegToTiffConverter::convert(input, output); + break; + case 23: // JPEG to WEBP + success = JpegToWebpConverter::convert(input, output); + break; + case 24: // PNG to JPEG + success = PngToJpegConverter::convert(input, output); + break; + case 25: // BMP to JPEG + success = BmpToJpegConverter::convert(input, output); + break; + case 26: // TIFF to JPEG + success = TiffToJpegConverter::convert(input, output); + break; + case 27: // WEBP to JPEG + success = WebpToJpegConverter::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 7e78aec..267fe11 100644 --- a/others/C++/Image_format_converter/src/image_loader.cpp +++ b/others/C++/Image_format_converter/src/image_loader.cpp @@ -2,32 +2,108 @@ #include "common.hpp" #include #include +#include +#include #include #include +#include + +static bool is_webp_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, "RIFF", 4) && !memcmp(header + 8, "WEBP", 4); +} 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())); + // 检查是否为WebP格式 + if (is_webp_file(path)) { + // 读取WebP文件数据 + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file) { + throw std::runtime_error("无法打开WebP文件"); + } + + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); + + std::vector webp_data(size); + if (!file.read(reinterpret_cast(webp_data.data()), size)) { + throw std::runtime_error("无法读取WebP文件"); + } + + // 解码WebP图像 + WebPBitstreamFeatures features; + if (WebPGetFeatures(webp_data.data(), webp_data.size(), &features) != VP8_STATUS_OK) { + throw std::runtime_error("无效的WebP图像"); + } + + data.width = features.width; + data.height = features.height; + data.channels = features.has_alpha ? 4 : 3; + + // 解码WebP图像为RGBA格式 + uint8_t* rgba_pixels = WebPDecodeRGBA(webp_data.data(), webp_data.size(), &data.width, &data.height); + if (!rgba_pixels) { + throw std::runtime_error("无法解码WebP图像"); + } + + // 如果没有alpha通道,转换为RGB格式 + if (data.channels == 3) { + uint8_t* rgb_pixels = new uint8_t[data.width * data.height * 3]; + for (int i = 0; i < data.width * data.height; ++i) { + rgb_pixels[i*3] = rgba_pixels[i*4]; + rgb_pixels[i*3+1] = rgba_pixels[i*4+1]; + rgb_pixels[i*3+2] = rgba_pixels[i*4+2]; + } + WebPFree(rgba_pixels); + + // 验证图像数据 + try { + validate_image(rgb_pixels, data.width, data.height); + } catch (...) { + delete[] rgb_pixels; + throw; + } + + data.pixels = std::unique_ptr(rgb_pixels, [](void* p) { delete[] static_cast(p); }); + } else { + // 验证图像数据 + try { + validate_image(rgba_pixels, data.width, data.height); + } catch (...) { + WebPFree(rgba_pixels); + throw; + } + + data.pixels = std::unique_ptr(rgba_pixels, WebPFree); + } + } else { + // 使用STB加载其他格式图像 + 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 = std::unique_ptr(pixels, stbi_image_free); } - - // 验证图像数据 - try { - validate_image(pixels, data.width, data.height); - } catch (...) { - stbi_image_free(pixels); - throw; - } - - // 转移所有权到智能指针 - data.pixels.reset(pixels); return data; } diff --git a/others/C++/Image_format_converter/src/jpeg_to_bmp.cpp b/others/C++/Image_format_converter/src/jpeg_to_bmp.cpp new file mode 100644 index 0000000..8c0b238 --- /dev/null +++ b/others/C++/Image_format_converter/src/jpeg_to_bmp.cpp @@ -0,0 +1,33 @@ +#include "jpeg_to_bmp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool JpegToBmpConverter::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_input(data)) { + return false; + } + + // 保存为BMP + return stbi_write_bmp(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get()); +} + +bool JpegToBmpConverter::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/jpeg_to_png.cpp b/others/C++/Image_format_converter/src/jpeg_to_png.cpp new file mode 100644 index 0000000..505790a --- /dev/null +++ b/others/C++/Image_format_converter/src/jpeg_to_png.cpp @@ -0,0 +1,34 @@ +#include "jpeg_to_png.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool JpegToPngConverter::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_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 JpegToPngConverter::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/jpeg_to_tiff.cpp b/others/C++/Image_format_converter/src/jpeg_to_tiff.cpp new file mode 100644 index 0000000..8bc4124 --- /dev/null +++ b/others/C++/Image_format_converter/src/jpeg_to_tiff.cpp @@ -0,0 +1,61 @@ +#include "jpeg_to_tiff.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool JpegToTiffConverter::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_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 JpegToTiffConverter::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/jpeg_to_webp.cpp b/others/C++/Image_format_converter/src/jpeg_to_webp.cpp new file mode 100644 index 0000000..0f3c9c5 --- /dev/null +++ b/others/C++/Image_format_converter/src/jpeg_to_webp.cpp @@ -0,0 +1,61 @@ +#include "jpeg_to_webp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool JpegToWebpConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 加载JPEG图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(data)) { + return false; + } + + // 编码为WebP + uint8_t* output = nullptr; + size_t output_size; + if (data.channels == 3) { + output_size = WebPEncodeRGB(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } else { + output_size = WebPEncodeRGBA(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } + + if (output_size == 0) { + return false; + } + + // 保存WebP文件 + FILE* file = fopen(output_path.c_str(), "wb"); + if (!file) { + WebPFree(output); + return false; + } + + fwrite(output, 1, output_size, file); + fclose(file); + WebPFree(output); + return true; +} + +bool JpegToWebpConverter::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/jpg_to_webp.cpp b/others/C++/Image_format_converter/src/jpg_to_webp.cpp new file mode 100644 index 0000000..43979da --- /dev/null +++ b/others/C++/Image_format_converter/src/jpg_to_webp.cpp @@ -0,0 +1,61 @@ +#include "jpg_to_webp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool JpgToWebpConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 加载JPG图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(data)) { + return false; + } + + // 编码为WebP + uint8_t* output = nullptr; + size_t output_size; + if (data.channels == 3) { + output_size = WebPEncodeRGB(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } else { + output_size = WebPEncodeRGBA(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } + + if (output_size == 0) { + return false; + } + + // 保存WebP文件 + FILE* file = fopen(output_path.c_str(), "wb"); + if (!file) { + WebPFree(output); + return false; + } + + fwrite(output, 1, output_size, file); + fclose(file); + WebPFree(output); + return true; +} + +bool JpgToWebpConverter::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_jpeg.cpp b/others/C++/Image_format_converter/src/png_to_jpeg.cpp new file mode 100644 index 0000000..87a039f --- /dev/null +++ b/others/C++/Image_format_converter/src/png_to_jpeg.cpp @@ -0,0 +1,35 @@ +#include "png_to_jpeg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool PngToJpegConverter::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; + } + + // 保存为JPEG + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +bool PngToJpegConverter::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_webp.cpp b/others/C++/Image_format_converter/src/png_to_webp.cpp new file mode 100644 index 0000000..34cb2c4 --- /dev/null +++ b/others/C++/Image_format_converter/src/png_to_webp.cpp @@ -0,0 +1,61 @@ +#include "png_to_webp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool PngToWebpConverter::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; + } + + // 编码为WebP + uint8_t* output = nullptr; + size_t output_size; + if (data.channels == 3) { + output_size = WebPEncodeRGB(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } else { + output_size = WebPEncodeRGBA(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } + + if (output_size == 0) { + return false; + } + + // 保存WebP文件 + FILE* file = fopen(output_path.c_str(), "wb"); + if (!file) { + WebPFree(output); + return false; + } + + fwrite(output, 1, output_size, file); + fclose(file); + WebPFree(output); + return true; +} + +bool PngToWebpConverter::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/tiff_to_jpeg.cpp b/others/C++/Image_format_converter/src/tiff_to_jpeg.cpp new file mode 100644 index 0000000..3ace3e3 --- /dev/null +++ b/others/C++/Image_format_converter/src/tiff_to_jpeg.cpp @@ -0,0 +1,73 @@ +#include "tiff_to_jpeg.hpp" +#include "common.hpp" +#include +#include +#include + +bool TiffToJpegConverter::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; + } + + // 保存为JPEG + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +bool TiffToJpegConverter::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_webp.cpp b/others/C++/Image_format_converter/src/tiff_to_webp.cpp new file mode 100644 index 0000000..ee1ebf7 --- /dev/null +++ b/others/C++/Image_format_converter/src/tiff_to_webp.cpp @@ -0,0 +1,61 @@ +#include "tiff_to_webp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include + +bool TiffToWebpConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 加载TIFF图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(data)) { + return false; + } + + // 编码为WebP + uint8_t* output = nullptr; + size_t output_size; + if (data.channels == 3) { + output_size = WebPEncodeRGB(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } else { + output_size = WebPEncodeRGBA(data.pixels.get(), + data.width, + data.height, + data.width * data.channels, + quality, + &output); + } + + if (output_size == 0) { + return false; + } + + // 保存WebP文件 + FILE* file = fopen(output_path.c_str(), "wb"); + if (!file) { + WebPFree(output); + return false; + } + + fwrite(output, 1, output_size, file); + fclose(file); + WebPFree(output); + return true; +} + +bool TiffToWebpConverter::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/utils.cpp b/others/C++/Image_format_converter/src/utils.cpp index b3d8398..a6e3b81 100644 --- a/others/C++/Image_format_converter/src/utils.cpp +++ b/others/C++/Image_format_converter/src/utils.cpp @@ -7,5 +7,7 @@ ImageFormat get_format_from_extension(const std::string& path) { if (ext == "png") return ImageFormat::PNG; if (ext == "jpg" || ext == "jpeg") return ImageFormat::JPG; + if (ext == "tif" || ext == "tiff") return ImageFormat::TIFF; + if (ext == "webp") return ImageFormat::WEBP; return ImageFormat::UNKNOWN; } diff --git a/others/C++/Image_format_converter/src/webp_to_bmp.cpp b/others/C++/Image_format_converter/src/webp_to_bmp.cpp new file mode 100644 index 0000000..6c3de87 --- /dev/null +++ b/others/C++/Image_format_converter/src/webp_to_bmp.cpp @@ -0,0 +1,33 @@ +#include "webp_to_bmp.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool WebpToBmpConverter::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_input(data)) { + return false; + } + + // 保存为BMP + return stbi_write_bmp(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get()); +} + +bool WebpToBmpConverter::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/webp_to_jpeg.cpp b/others/C++/Image_format_converter/src/webp_to_jpeg.cpp new file mode 100644 index 0000000..0146436 --- /dev/null +++ b/others/C++/Image_format_converter/src/webp_to_jpeg.cpp @@ -0,0 +1,35 @@ +#include "webp_to_jpeg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool WebpToJpegConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 加载WebP图像 + ImageData data = ImageLoader::load(input_path); + if (!data.pixels) { + return false; + } + + // 验证输入格式 + if (!validate_input(data)) { + return false; + } + + // 保存为JPEG + return stbi_write_jpg(output_path.c_str(), + data.width, + data.height, + data.channels, + data.pixels.get(), + quality); +} + +bool WebpToJpegConverter::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/webp_to_jpg.cpp b/others/C++/Image_format_converter/src/webp_to_jpg.cpp new file mode 100644 index 0000000..ea9b67a --- /dev/null +++ b/others/C++/Image_format_converter/src/webp_to_jpg.cpp @@ -0,0 +1,35 @@ +#include "webp_to_jpg.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool WebpToJpgConverter::convert(const std::string& input_path, + const std::string& output_path, + int quality) { + // 加载WebP图像 + 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 WebpToJpgConverter::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/webp_to_png.cpp b/others/C++/Image_format_converter/src/webp_to_png.cpp new file mode 100644 index 0000000..f429fbe --- /dev/null +++ b/others/C++/Image_format_converter/src/webp_to_png.cpp @@ -0,0 +1,34 @@ +#include "webp_to_png.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool WebpToPngConverter::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_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 WebpToPngConverter::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/webp_to_tiff.cpp b/others/C++/Image_format_converter/src/webp_to_tiff.cpp new file mode 100644 index 0000000..cdbd78e --- /dev/null +++ b/others/C++/Image_format_converter/src/webp_to_tiff.cpp @@ -0,0 +1,78 @@ +#include "webp_to_tiff.hpp" +#include "common.hpp" +#include "image_loader.hpp" +#include +#include +#include + +bool WebpToTiffConverter::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_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); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, + data.channels == 3 ? PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW); + + // 写入图像数据 + tsize_t linebytes = data.width * data.channels; + unsigned char* buf = nullptr; + if (TIFFScanlineSize(tif) == linebytes) { + buf = (unsigned char*)data.pixels.get() + + (data.height - 1) * linebytes; + for (uint32 row = 0; row < data.height; row++) { + if (TIFFWriteScanline(tif, buf, row, 0) < 0) { + TIFFClose(tif); + return false; + } + buf -= linebytes; + } + } else { + buf = (unsigned char*)_TIFFmalloc(linebytes); + if (!buf) { + TIFFClose(tif); + return false; + } + unsigned char* src = (unsigned char*)data.pixels.get(); + for (uint32 row = 0; row < data.height; row++) { + memcpy(buf, src, linebytes); + if (TIFFWriteScanline(tif, buf, row, 0) < 0) { + _TIFFfree(buf); + TIFFClose(tif); + return false; + } + src += linebytes; + } + _TIFFfree(buf); + } + + TIFFClose(tif); + return true; +} + +bool WebpToTiffConverter::validate_input(const ImageData& data) { + // 确保是有效的图像数据 + return data.width > 0 && data.height > 0 && + (data.channels == 3 || data.channels == 4); +}