当前位置: 首页 > wzjs >正文

网站的四大要素关键词优化快排

网站的四大要素,关键词优化快排,广州做礼物的网站,学做网站需要什么基础PNG图像压缩优化工具 标题:PNG图像三重压缩优化系统 介绍大纲 1. 工具概述 基于libimagequant和libpng的高效PNG压缩工具提供三种不同级别的压缩算法支持保留透明度和色彩质量优化 2. 核心功能 ​​基础压缩​​ (compress_png): 标准量化处理中等压…

PNG图像压缩优化工具

标题:PNG图像三重压缩优化系统

介绍大纲

1. 工具概述

  • 基于libimagequant和libpng的高效PNG压缩工具
  • 提供三种不同级别的压缩算法
  • 支持保留透明度和色彩质量优化

2. 核心功能

  • ​基础压缩​​ (compress_png):

    • 标准量化处理
    • 中等压缩率和处理速度
    • 适合大多数常规用途
  • ​优化压缩​​ (compress_png_optimized):

    • 增强的量化参数设置
    • 更低的抖动级别
    • 更高的压缩级别(9)
    • 适合需要更好压缩率的场景
  • ​极限压缩​​ (compress_png_max_compression):

    • 激进的颜色减少预处理
    • 相似颜色合并算法
    • 最低质量范围设置(0-30)
    • 适合对文件大小极度敏感的场景

3. 技术特点

  • 现代C++实现(使用C++17特性)

  • RAII资源管理(智能指针管理资源)

  • 多阶段压缩管道:

    1. 图像读取与解码
    2. 颜色预处理(极限压缩模式)
    3. 量化与调色板优化
    4. PNG编码与压缩
  • 支持的功能:

    • 透明度保留
    • 颜色相似度合并
    • 自适应抖动控制
    • 多种PNG过滤策略

4. 性能指标

  • 压缩率比较:

    • 基础压缩:中等压缩率
    • 优化压缩:比基础高10-20%
    • 极限压缩:比基础高20-40%
  • 处理速度:

    • 基础压缩:最快
    • 优化压缩:中等
    • 极限压缩:最慢(质量优先)

5. 使用场景

  • 网页图像优化
  • 移动应用资源压缩
  • 游戏素材处理
  • 批量图像处理流水线

6. 扩展性

  • 可轻松集成到现有系统
  • 模块化设计便于添加新算法
  • 支持自定义压缩参数

7. 示例输出

  • 提供三种压缩级别的结果比较
  • 输出详细的压缩统计信息:
    • 原始大小
    • 压缩后大小
    • 压缩百分比
    • 处理时间(可选)
#include <iostream>
#include <fstream>
#include <vector>
#include <memory>
#include <filesystem>
#include <cstring>
#include <cmath>
#include <png.h>
#include <string>
#include <iomanip>
#include "libimagequant.h"
#include "png_manager.hpp"
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "userenv.lib")
#pragma comment(lib, "ntdll.lib")
// 自定义删除器用于 liq_attr 指针
struct LiqAttrDeleter {void operator()(liq_attr* attr) const {if (attr) liq_attr_destroy(attr);}
};// 自定义删除器用于 liq_image 指针
struct LiqImageDeleter {void operator()(liq_image* image) const {if (image) liq_image_destroy(image);}
};// 自定义删除器用于 liq_result 指针
struct LiqResultDeleter {void operator()(liq_result* res) const {if (res) liq_result_destroy(res);}
};// 使用现代 C++ 类型别名
using UniqueLiqAttr = std::unique_ptr<liq_attr, LiqAttrDeleter>;
using UniqueLiqImage = std::unique_ptr<liq_image, LiqImageDeleter>;
using UniqueLiqResult = std::unique_ptr<liq_result, LiqResultDeleter>;// PNG 内存读取结构
struct MemoryReaderState {const unsigned char* data;size_t size;size_t offset;
};// PNG 内存写入结构
struct MemoryWriterState {std::vector<unsigned char>* buffer;
};// 扩展 PngManager 类以支持索引图像
class ExtendedPngManager : public PngManager {
public:// 写入索引图像到内存PngManager::ErrorCode WriteIndexedToMemory(uint32_t width, uint32_t height,const std::vector<uint8_t>& indexes,   // 索引数据,大小为 width * heightconst std::vector<png_color>& palette,   // 调色板const std::vector<uint8_t>& trans,       // 调色板的透明度(可选)std::vector<uint8_t>& outBuffer,int compressionLevel = 6){if (indexes.size() != width * height) {return PngManager::ErrorCode::InvalidParameters;}if (palette.empty() || palette.size() > 256) {return PngManager::ErrorCode::InvalidParameters;}// 初始化写入结构png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);if (!pngPtr) {return PngManager::ErrorCode::CreateWriteStructFailed;}png_infop infoPtr = png_create_info_struct(pngPtr);if (!infoPtr) {png_destroy_write_struct(&pngPtr, nullptr);return PngManager::ErrorCode::CreateInfoStructFailed;}// 错误处理设置if (setjmp(png_jmpbuf(pngPtr))) {png_destroy_write_struct(&pngPtr, &infoPtr);return PngManager::ErrorCode::PngProcessingError;}// 设置内存写入回调struct WriteContext {std::vector<uint8_t>* buffer;} ctx{ &outBuffer };png_set_write_fn(pngPtr, &ctx, [](png_structp pngPtr, png_bytep data, png_size_t length) {auto* ctx = static_cast<WriteContext*>(png_get_io_ptr(pngPtr));size_t oldSize = ctx->buffer->size();ctx->buffer->resize(oldSize + length);memcpy(ctx->buffer->data() + oldSize, data, length);}, nullptr);// 设置压缩级别png_set_compression_level(pngPtr, compressionLevel);// 设置IHDR:索引模式png_set_IHDR(pngPtr, infoPtr, width, height, 8,PNG_COLOR_TYPE_PALETTE, // 索引颜色PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);// 设置调色板png_color paletteArray[256];int paletteSize = static_cast<int>(palette.size());if (paletteSize > 256) paletteSize = 256;for (int i = 0; i < paletteSize; i++) {paletteArray[i] = palette[i];}png_set_PLTE(pngPtr, infoPtr, paletteArray, paletteSize);// 设置透明度(tRNS)块if (!trans.empty()) {// 如果trans的大小小于调色板大小,则只设置前面的部分int transSize = static_cast<int>(trans.size()) < paletteSize ? static_cast<int>(trans.size()) : paletteSize;png_byte transArray[256];for (int i = 0; i < transSize; i++) {transArray[i] = trans[i];}png_set_tRNS(pngPtr, infoPtr, transArray, transSize, nullptr);}// 写入信息头png_write_info(pngPtr, infoPtr);// 准备行指针std::vector<png_bytep> rowPointers(height);for (uint32_t y = 0; y < height; ++y) {// 注意:indexes是一维数组,按行存储// 由于indexes是const,但libpng要求非const指针,所以需要const_cast。但注意,libpng不会修改数据。rowPointers[y] = const_cast<png_bytep>(&indexes[y * width]);}// 写入图像数据png_write_image(pngPtr, rowPointers.data());png_write_end(pngPtr, nullptr);// 清理png_destroy_write_struct(&pngPtr, &infoPtr);return PngManager::ErrorCode::Success;}// 写入索引图像到文件PngManager::ErrorCode WriteIndexedToFile(uint32_t width, uint32_t height,const std::vector<uint8_t>& indexes,const std::vector<png_color>& palette,const std::vector<uint8_t>& trans,const std::filesystem::path& path,int compressionLevel = 6){std::vector<uint8_t> outBuffer;ErrorCode err = WriteIndexedToMemory(width, height, indexes, palette, trans, outBuffer, compressionLevel);if (err != ErrorCode::Success) {return err;}// 将内存数据写入文件std::ofstream file(path, std::ios::binary);if (!file) {return ErrorCode::PngProcessingError;}file.write(reinterpret_cast<const char*>(outBuffer.data()), outBuffer.size());return ErrorCode::Success;}
};// 从文件读取数据到内存
std::vector<uint8_t> read_file_to_memory(const std::filesystem::path& path) {std::ifstream file(path, std::ios::binary | std::ios::ate);if (!file) {throw std::runtime_error("无法打开文件: " + path.string());}// 获取文件大小const size_t file_size = file.tellg();file.seekg(0);// 读取整个文件到内存std::vector<uint8_t> buffer(file_size);if (!file.read(reinterpret_cast<char*>(buffer.data()), file_size)) {throw std::runtime_error("读取文件失败: " + path.string());}return buffer;
}// 压缩 PNG 图像的函数
bool compress_png(const std::filesystem::path& input_path,const std::filesystem::path& output_path,int max_colors = 256,float dither_level = 1.0f) {try {ExtendedPngManager pngManager;// 1. 读取输入文件到内存std::vector<uint8_t> fileContent = read_file_to_memory(input_path);// 2. 使用PngManager读取PNG数据PngManager::ImageData imageData;auto error = pngManager.ReadFromMemory(fileContent.data(), fileContent.size(), imageData);if (error != PngManager::ErrorCode::Success) {throw std::runtime_error("Failed to read PNG file: " + std::to_string(static_cast<int>(error)));}int width = static_cast<int>(imageData.width);int height = static_cast<int>(imageData.height);int channels = (imageData.format == PngManager::PixelFormat::RGBA) ? 4 :(imageData.format == PngManager::PixelFormat::RGB) ? 3 :(imageData.format == PngManager::PixelFormat::GrayscaleAlpha) ? 2 : 1;std::cout << "Processing image: " << width << " x " << height << " pixels"<< ", Channels: " << channels << "\n";// 3. 创建 liq_attr 对象UniqueLiqAttr attr(liq_attr_create());if (!attr) {throw std::runtime_error("Failed to create liq_attr object");}// 设置量化参数liq_set_max_colors(attr.get(), max_colors);liq_set_speed(attr.get(), 5); // 中等速度预设// 对于RGBA图像(带透明度),设置最小不透明度if (channels == 4) {liq_set_min_opacity(attr.get(), 0); // 保留全透明像素}// 4. 创建图像对象UniqueLiqImage image(liq_image_create_rgba(attr.get(), imageData.pixels.data(), width, height, 0));if (!image) {throw std::runtime_error("Failed to create image object");}// 5. 执行量化liq_result* raw_result = liq_quantize_image(attr.get(), image.get());if (!raw_result) {throw std::runtime_error("Quantization failed: liq_quantize_image returned null");}UniqueLiqResult result(raw_result);// 6. 设置抖动水平liq_set_dithering_level(result.get(), dither_level);// 7. 准备索引图像std::vector<uint8_t> indexed_data(width * height);liq_error remap_err = liq_write_remapped_image(result.get(), image.get(), indexed_data.data(), indexed_data.size());if (remap_err != LIQ_OK) {throw std::runtime_error("Remapping image failed: " + std::to_string(remap_err));}// 8. 获取调色板const liq_palette* palette_ptr = liq_get_palette(result.get());if (!palette_ptr) {throw std::runtime_error("Failed to get palette");}// 9. 检查调色板透明度bool has_transparency = false;if (channels == 4) { // 仅当原始图像有透明度时才检查for (int i = 0; i < palette_ptr->count; i++) {if (palette_ptr->entries[i].a < 255) {has_transparency = true;break;}}if (has_transparency) {std::cout << "Preserved transparency in palette\n";}}// 10. 准备调色板和透明度数据std::vector<png_color> pngPalette;std::vector<uint8_t> trans;for (int i = 0; i < palette_ptr->count; i++) {png_color c;c.red = palette_ptr->entries[i].r;c.green = palette_ptr->entries[i].g;c.blue = palette_ptr->entries[i].b;pngPalette.push_back(c);// 如果图像有透明度,才收集trans数据if (has_transparency) {trans.push_back(palette_ptr->entries[i].a);}}if (!has_transparency) {trans.clear();}// 11. 保存索引图像error = pngManager.WriteIndexedToFile(width, height, indexed_data, pngPalette, trans, output_path);if (error != PngManager::ErrorCode::Success) {throw std::runtime_error("Failed to write indexed PNG: " + std::to_string(static_cast<int>(error)));}// 12. 计算压缩率size_t original_size = fileContent.size();size_t compressed_size = std::filesystem::file_size(output_path);double reduction = (original_size > 0) ? 100.0 * (1.0 - static_cast<double>(compressed_size) / original_size) : 0.0;std::cout << "Successfully compressed image ("<< original_size << " bytes -> " << compressed_size << " bytes, "<< std::fixed << std::setprecision(1) << reduction << "% reduction)\n"<< "Saved as: " << output_path << std::endl;return true;}catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return false;}
}
bool compress_png_optimized(const std::filesystem::path& input_path,const std::filesystem::path& output_path,int max_colors = 128,float dither_level = 0.7f) {try {ExtendedPngManager pngManager;std::vector<uint8_t> fileContent = read_file_to_memory(input_path);PngManager::ImageData imageData;auto error = pngManager.ReadFromMemory(fileContent.data(), fileContent.size(), imageData);if (error != PngManager::ErrorCode::Success) {throw std::runtime_error("Failed to read PNG file");}int width = static_cast<int>(imageData.width);int height = static_cast<int>(imageData.height);int channels = (imageData.format == PngManager::PixelFormat::RGBA) ? 4 : 3;// 1. 创建并配置liq_attrUniqueLiqAttr attr(liq_attr_create());liq_set_max_colors(attr.get(), max_colors);liq_set_speed(attr.get(), 1); // 最慢但质量最好liq_set_quality(attr.get(), 0, 30); // 质量范围if (channels == 4) {liq_set_min_opacity(attr.get(), 0);}// 2. 创建图像并量化UniqueLiqImage image(liq_image_create_rgba(attr.get(), imageData.pixels.data(), width, height, 0));UniqueLiqResult result(liq_quantize_image(attr.get(), image.get()));liq_set_dithering_level(result.get(), dither_level);// 3. 准备输出数据std::vector<uint8_t> indexed_data(width * height);liq_write_remapped_image(result.get(), image.get(), indexed_data.data(), indexed_data.size());// 4. 获取并优化调色板const liq_palette* palette_ptr = liq_get_palette(result.get());std::vector<png_color> pngPalette;std::vector<uint8_t> trans;for (int i = 0; i < palette_ptr->count; i++) {png_color c = { palette_ptr->entries[i].r, palette_ptr->entries[i].g, palette_ptr->entries[i].b };pngPalette.push_back(c);if (channels == 4) trans.push_back(palette_ptr->entries[i].a);}// 5. 使用最高压缩级别写入error = pngManager.WriteIndexedToFile(width, height, indexed_data, pngPalette, trans, output_path, 9);// 报告压缩结果size_t original_size = fileContent.size();size_t compressed_size = std::filesystem::file_size(output_path);double reduction = 100.0 * (1.0 - static_cast<double>(compressed_size) / original_size);std::cout << "Optimized compression: " << reduction << "% reduction\n";return true;}catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return false;}
}
#include <algorithm>
#include <vector>
#include <cmath>bool compress_png_max_compression(const std::filesystem::path& input_path,const std::filesystem::path& output_path,int max_colors = 64,            // 更少的颜色数量float dither_level = 0.5f)      // 更低的抖动级别
{try {ExtendedPngManager pngManager;// 1. 读取输入文件std::vector<uint8_t> fileContent = read_file_to_memory(input_path);PngManager::ImageData imageData;auto error = pngManager.ReadFromMemory(fileContent.data(), fileContent.size(), imageData);if (error != PngManager::ErrorCode::Success) {throw std::runtime_error("Failed to read PNG file");}const int width = static_cast<int>(imageData.width);const int height = static_cast<int>(imageData.height);const int channels = (imageData.format == PngManager::PixelFormat::RGBA) ? 4 : 3;// 2. 预处理图像 - 减少颜色变化if (channels >= 3) {auto& pixels = imageData.pixels;const float color_reduction = 0.9f; // 颜色减少强度 (0.0-1.0)for (size_t i = 0; i < pixels.size(); i += channels) {// 对RGB通道进行轻微的颜色量化for (int c = 0; c < 3; c++) {float val = pixels[i + c];val = std::round(val / (color_reduction * 10 + 5)) * (color_reduction * 10 + 5);pixels[i + c] = static_cast<uint8_t>(std::clamp(val, 0.0f, 255.0f));}}}// 3. 配置量化参数 - 优化压缩UniqueLiqAttr attr(liq_attr_create());liq_set_max_colors(attr.get(), max_colors);              // 更少的颜色liq_set_speed(attr.get(), 1);                            // 最慢但质量最好liq_set_quality(attr.get(), 0, 30);                      // 更低的质量范围liq_set_min_posterization(attr.get(), 1);                // 减少色带if (channels == 4) {liq_set_min_opacity(attr.get(), 15);                 // 合并接近透明的像素}// 4. 创建图像并量化UniqueLiqImage image(liq_image_create_rgba(attr.get(), imageData.pixels.data(), width, height, 0));UniqueLiqResult result(liq_quantize_image(attr.get(), image.get()));liq_set_dithering_level(result.get(), dither_level);     // 更少的抖动// 5. 准备输出数据std::vector<uint8_t> indexed_data(width * height);liq_write_remapped_image(result.get(), image.get(), indexed_data.data(), indexed_data.size());// 6. 获取并优化调色板const liq_palette* palette_ptr = liq_get_palette(result.get());std::vector<png_color> pngPalette;std::vector<uint8_t> trans;// 合并相似颜色const int color_tolerance = 8; // 颜色相似度容差for (int i = 0; i < palette_ptr->count; ) {png_color current = {palette_ptr->entries[i].r,palette_ptr->entries[i].g,palette_ptr->entries[i].b};// 尝试合并相似颜色bool merged = false;for (auto& existing : pngPalette) {if (abs(existing.red - current.red) < color_tolerance &&abs(existing.green - current.green) < color_tolerance &&abs(existing.blue - current.blue) < color_tolerance) {merged = true;break;}}if (!merged) {pngPalette.push_back(current);if (channels == 4) {trans.push_back(palette_ptr->entries[i].a);}}i++;}// 7. 使用最高压缩参数写入error = pngManager.WriteIndexedToFile(width, height,indexed_data,pngPalette,trans,output_path,9                          // 最高压缩级别);if (error != PngManager::ErrorCode::Success) {throw std::runtime_error("Failed to write compressed PNG");}// 报告压缩结果size_t original_size = fileContent.size();size_t compressed_size = std::filesystem::file_size(output_path);double reduction = 100.0 * (1.0 - static_cast<double>(compressed_size) / original_size);std::cout << "Max compression: " << reduction << "% reduction ("<< original_size << " bytes -> " << compressed_size << " bytes)\n";return true;}catch (const std::runtime_error& e) {std::cerr << "Compression error: " << e.what() << std::endl;return false;}catch (...) {std::cerr << "Unknown error during compression" << std::endl;return false;}
}
int main() {const std::filesystem::path input_path = "D:\\png_compress\\test.png";const std::filesystem::path output_path = "D:\\png_compress\\test_compresseded.png";const std::filesystem::path output_optimized_path = "D:\\png_compress\\test_compresseded_optimized.png";const std::filesystem::path output_max_optimized_path = "D:\\png_compress\\test_compresseded_max_optimized.png";// 检查输入文件是否存在if (!std::filesystem::exists(input_path)) {std::cerr << "Input file does not exist: " << input_path << std::endl;return 1;}// 执行压缩(启用透明度保护和中等抖动)if (!compress_png(input_path, output_path, 256, 0.8f)) {std::cerr << "Image compression failed" << std::endl;return 1;}// 执行压缩(启用透明度保护和中等抖动)if (!compress_png_optimized(input_path, output_optimized_path, 256, 0.8f)) {std::cerr << "Image compression failed" << std::endl;return 1;}// 执行压缩(启用透明度保护和中等抖动)if (!compress_png_max_compression(input_path, output_max_optimized_path, 64, 0.8f)) {std::cerr << "Image compression failed" << std::endl;return 1;}return 0;
}
http://www.dtcms.com/wzjs/254847.html

相关文章:

  • 网站后天添加文章不显示白云区新闻
  • 推荐做流程图的网站北京seo优化哪家好
  • 哪个网站可以做字体大小网络营销方案3000字
  • 旅游网站设计模版深圳竞价排名网络推广
  • 企业网站排名怎么优化怎么做公司网站推广
  • 怎么优化网站网站名查询网址
  • 百度手机模板网站需要优化的地方
  • 做网站的主要收入建立网站费用大概需要多少钱
  • 支付网站建设费网络营销的步骤
  • 政府网站建设的国际外包seo公司
  • 建设银行手机登录网站网站建设的基本流程
  • 网站建站工具有哪些关键词搜索量全网查询
  • 餐厅网站开发背景百度指数批量查询工具
  • 凡科快图在线抠图桂林网站优化
  • 做网站开发的公司安装百度
  • 个人养老保险怎么交seo搜索引擎优化软件
  • 中国都在那个网站上做外贸北京网站优化服务
  • 网站部署环境怎么找需要推广的商家
  • 漳州微网站建设价格浙江搜索引擎优化
  • 山西焦煤集团公司网站seo的优化步骤
  • 前端开发学哪些杭州做seo的公司
  • 网站优化报表东莞网络推广
  • 公司论坛网站建设规划书南宁百度seo价格
  • 商务网站建设网站开发今天刚刚发生的新闻事故
  • 那个网站做网编好编程培训机构
  • 哪个网站的图片可以做素材网站域名ip地址查询
  • 如果将域名指向网站万能识图
  • 免费建立国外网站潍坊百度seo公司
  • 扶风做企业网站石家庄百度快照优化
  • 微信小程序应用开发珠海seo推广