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

封装一个png的编码解码操作

文章目录

      • 像素数据与编码图像的区别详解
        • 1. ​**​像素数据 (Pixel Data)​**​
        • 2. ​**​编码图像 (Encoded Image)​**​
      • 处理流程中的转换关系
      • 在代码中的具体体现
      • 关键区别总结
      • 代码执行示例
      • 性能考量
    • 实现文件
    • 头文件

像素数据与编码图像的区别详解

在图像处理流程中,"像素数据"和"编码图像"代表两个完全不同的概念,它们处于图像处理管道的不同阶段:

1. ​​像素数据 (Pixel Data)​
  • ​定义​​:表示图像的原始、未压缩的点阵数据

  • ​结构​​:

    • 是一个连续的内存块
    • 每个像素包含RGB(A)分量(如RGBA格式是4字节/像素)
    • 格式示例:[R0,G0,B0,A0, R1,G1,B1,A1, ...]
  • ​特点​​:

    • 未压缩的原始格式
    • 占用较大内存(宽 × 高 × 字节数/像素)
    • 可直接用于图像处理操作(缩放、滤镜等)
    • 无额外元数据(颜色空间、压缩参数等)
  • ​代码中的位置​​:

    // 这是像素数据
    std::vector<uint8_t> pixels;
    
2. ​​编码图像 (Encoded Image)​
  • ​定义​​:经过特定算法压缩的图像二进制数据

  • ​结构​​:

    • 遵循特定格式标准(如PNG)
    • 包含文件头、元数据和压缩后的像素数据
    • 包含校验码、颜色空间信息等
  • ​特点​​:

    • 压缩格式(减少存储/传输体积)
    • 不可直接用于图像处理
    • 需要解码器才能获取像素数据
    • 包含完整文件结构和元数据
  • ​代码中的位置​​:

    // 这是编码图像
    std::vector<uint8_t> outputPng;
    

处理流程中的转换关系

graph LRA[原始编码图像] -->|解码| B[像素数据]B -->|插值缩放| C[新像素数据]C -->|编码| D[新编码图像]

在代码中的具体体现

  1. ​解码过程(获取像素数据)​​:

    // 原始PNG文件 → 像素数据
    PngManager::ImageData sourceImage;
    pngManager.ReadFromMemory(png_data.data(), png_data.size(), sourceImage);
    // sourceImage.pixels 现在是像素数据
    
  2. ​像素处理阶段​​:

    // 像素数据上执行插值
    ImageInterpolator::resize(input, width, height, method);
    // 直接操作像素数组
    
  3. ​编码过程(生成新图像)​​:

    // 处理后的像素数据 → PNG格式
    PngManager pngManager;
    std::vector<uint8_t> outputPng;
    pngManager.WriteToMemory(targetImage, outputPng);
    // outputPng 现在是可保存的PNG文件
    

关键区别总结

特性像素数据编码图像
​格式​原始数组(RGBA序列)压缩二进制格式(PNG/JPEG)
​大小​较大(宽×高×字节数/像素)较小(压缩后)
​可处理性​可直接处理需解码后使用
​元数据​包含EXIF、ICC等元数据
​平台兼容性​平台无关格式相关
​内存结构​简单连续内存复杂数据块结构
​典型用途​图像处理操作存储/传输

代码执行示例

// 1. 加载编码图像(PNG文件)
std::vector<uint8_t> encodedData = LoadPNG("input.png");// 2. 解码获取像素数据
PngManager::ImageData pixelData;
pngManager.ReadFromMemory(encodedData, pixelData);// 3. 处理像素数据
for (auto& pixel : pixelData.pixels) {pixel = 255 - pixel; // 反相处理
}// 4. 编码为新图像
std::vector<uint8_t> newEncodedImage;
pngManager.WriteToMemory(pixelData, newEncodedImage);// 5. 保存编码图像
SavePNG(newEncodedImage, "output.png");

性能考量

  1. ​解码/编码开销​​:

    • PNG解码:100×100图像约0.5ms
    • PNG编码:100×100图像约1.2ms
    • 如果处理流程涉及多次缩放操作,应保持在像素数据状态
  2. ​内存占用​​:

    1024×1024图像:- 像素数据(RGBA):4MB- 编码图像(PNG):约0.5-1.5MB
    

理解这两种数据类型的区别对于优化图像处理流程至关重要。在需要多次操作的场景(如缩放到多种尺寸),应在像素数据状态完成所有操作后统一编码,避免重复解码/编码的开销。

实现文件


class DIBitmapConverter {
public:// 从位图获取图像数据struct ImageData {std::vector<uint8_t> rgbData;    // RGB/RGBA数据std::vector<uint8_t> smaskData;  // 透明蒙版数据unsigned int width = 0;unsigned int height = 0;bool hasAlpha = false;};// 从 CFX_DIBitmap 获取图像数据static ImageData GetImageData(CFX_DIBitmap* bitmap, bool includeAlpha = true) {ImageData result;result.width = bitmap->GetWidth();result.height = bitmap->GetHeight();int format = bitmap->GetFormat();result.hasAlpha = (includeAlpha && HasAlphaChannel(format));// 计算数据大小size_t rgbSize = result.width * result.height * (result.hasAlpha ? 4 : 3);size_t smaskSize = result.width * result.height;result.rgbData.resize(rgbSize);result.smaskData.resize(smaskSize);// 获取位图数据uint8_t* bitmapData = static_cast<uint8_t*>(bitmap->GetBuffer());int stride = bitmap->GetPitch();int bpp = GetBPPFromFormat(format);
#if 0for (unsigned int y = 0; y < result.height; ++y) {for (unsigned int x = 0; x < result.width; ++x) {size_t srcOffset = y * stride + x * (bpp / 8);size_t rgbOffset = (y * result.width + x) * (result.hasAlpha ? 4 : 3);size_t smaskOffset = y * result.width + x;ExtractPixelData(bitmapData, srcOffset, format,result.rgbData, rgbOffset,result.smaskData, smaskOffset,result.hasAlpha);}}
#else// 预先计算常量
const int bytesPerPixel = bpp / 8;
const bool hasAlpha = result.hasAlpha;
const int rgbStep = hasAlpha ? 4 : 3;
const size_t width = result.width;// 获取数据指针
uint8_t* srcData = bitmapData;
uint8_t* rgbDataPtr = result.rgbData.data();
uint8_t* smaskDataPtr = result.smaskData.data();for (unsigned int y = 0; y < result.height; ++y) {// 计算行起始位置uint8_t* rowSrc = srcData + y * stride;uint8_t* rowRgb = rgbDataPtr + y * width * rgbStep;uint8_t* rowSmask = smaskDataPtr + y * width;for (unsigned int x = 0; x < width; ++x) {// 直接使用指针而不是计算偏移量ExtractPixelData(rowSrc, format,rowRgb, rowSmask,hasAlpha);// 移动到下一个像素rowSrc += bytesPerPixel;rowRgb += rgbStep;rowSmask++;}
}
#endifreturn result;}// 将图像数据设置到位图static bool SetImageData(CFX_DIBitmap* bitmap, const ImageData& imageData) {unsigned int width = bitmap->GetWidth();unsigned int height = bitmap->GetHeight();int format = bitmap->GetFormat();int bpp = GetBPPFromFormat(format);// 验证尺寸if (width != imageData.width || height != imageData.height) {/*throw std::runtime_error("Image dimensions do not match bitmap");*/return false;}// 获取位图数据uint8_t* bitmapData = static_cast<uint8_t*>(bitmap->GetBuffer());int stride = bitmap->GetPitch();for (unsigned int y = 0; y < height; ++y) {for (unsigned int x = 0; x < width; ++x) {size_t dstOffset = y * stride + x * (bpp / 8);size_t rgbOffset = (y * width + x) * (imageData.hasAlpha ? 4 : 3);size_t smaskOffset = y * width + x;SetPixelData(bitmapData, dstOffset, format,imageData.rgbData, rgbOffset,imageData.smaskData, smaskOffset,imageData.hasAlpha);}}}// 创建新的 CFX_DIBitmap 并设置图像数据static std::unique_ptr<CFX_DIBitmap> CreateBitmapFromData(const ImageData& imageData,FXDIB_Format format = FXDIB_Rgba){auto bitmap = std::make_unique<CFX_DIBitmap>();if (!bitmap->Create(imageData.width, imageData.height, format, nullptr, 0)) {//throw std::runtime_error("Failed to create bitmap");
#if HasDebugImagestd::cerr << "Failed to create bitmap" << std::endl;
#endif}SetImageData(bitmap.get(), imageData);return bitmap;}private:// 获取位图格式的位深度static int GetBPPFromFormat(int format) {switch (format) {case FXDIB_1bppMask: return 1;case FXDIB_8bppMask:case FXDIB_8bppRgb:case FXDIB_8bppRgba:case FXDIB_8bppCmyk:case FXDIB_8bppCmyka: return 8;case FXDIB_Rgb: return 24;case FXDIB_Rgba:case FXDIB_Rgb32:case FXDIB_Argb:case FXDIB_Cmyk:case FXDIB_Cmyka: return 32;default: return 0;}}// 检查格式是否有Alpha通道static bool HasAlphaChannel(int format) {switch (format) {case FXDIB_8bppRgba:case FXDIB_Rgba:case FXDIB_Rgb32:case FXDIB_Argb:case FXDIB_8bppCmyka:case FXDIB_Cmyka: return true;default: return false;}}
#if 0// 从位图提取像素数据static bool ExtractPixelData(uint8_t* bitmapData, size_t srcOffset, int format,std::vector<uint8_t>& rgbData, size_t rgbOffset,std::vector<uint8_t>& smaskData, size_t smaskOffset,bool includeAlpha){switch (format) {case FXDIB_8bppMask:case FXDIB_8bppRgb:case FXDIB_8bppRgba:case FXDIB_8bppCmyk:case FXDIB_8bppCmyka: {// 8位格式处理uint8_t gray = bitmapData[srcOffset];rgbData[rgbOffset] = rgbData[rgbOffset + 1] = rgbData[rgbOffset + 2] = gray;if (includeAlpha && rgbData.size() > rgbOffset + 3) {rgbData[rgbOffset + 3] = 255;}smaskData[smaskOffset] = 255;break;}case FXDIB_Rgb: {// 24位RGB处理rgbData[rgbOffset] = bitmapData[srcOffset + 2];     // RrgbData[rgbOffset + 1] = bitmapData[srcOffset + 1]; // GrgbData[rgbOffset + 2] = bitmapData[srcOffset];     // Bif (includeAlpha && rgbData.size() > rgbOffset + 3) {rgbData[rgbOffset + 3] = 255;}smaskData[smaskOffset] = 255;break;}case FXDIB_Rgba:case FXDIB_Rgb32:case FXDIB_Argb: {// 32位带Alpha处理rgbData[rgbOffset] = bitmapData[srcOffset + 2];     // RrgbData[rgbOffset + 1] = bitmapData[srcOffset + 1]; // GrgbData[rgbOffset + 2] = bitmapData[srcOffset];     // Bif (includeAlpha) {if (rgbData.size() > rgbOffset + 3) {rgbData[rgbOffset + 3] = bitmapData[srcOffset + 3]; // A}smaskData[smaskOffset] = bitmapData[srcOffset + 3];    // A}else {smaskData[smaskOffset] = 255;}break;}default:
#if HasDebugImagestd::cerr << "Unsupported bitmap format" << std::endl;
#endif//throw std::runtime_error("Unsupported bitmap format");return false;}}
#elsestatic void ExtractPixelData(uint8_t* srcPtr, int format,uint8_t* rgbPtr, uint8_t* smaskPtr,bool hasAlpha)
{switch (format) {case FXDIB_8bppMask:case FXDIB_8bppRgb:case FXDIB_8bppRgba:case FXDIB_8bppCmyk:case FXDIB_8bppCmyka: {// 8位格式处理uint8_t gray = *srcPtr;rgbPtr[0] = gray;rgbPtr[1] = gray;rgbPtr[2] = gray;if (hasAlpha) {rgbPtr[3] = 0xFF; // 完全不透明}*smaskPtr = 0xFF;break;}case FXDIB_Rgb: {// 24位RGB处理rgbPtr[0] = srcPtr[2]; // RrgbPtr[1] = srcPtr[1]; // GrgbPtr[2] = srcPtr[0]; // Bif (hasAlpha) {rgbPtr[3] = 0xFF; // 完全不透明}*smaskPtr = 0xFF;break;}case FXDIB_Rgba:case FXDIB_Rgb32:case FXDIB_Argb: {// 32位带Alpha处理rgbPtr[0] = srcPtr[2]; // RrgbPtr[1] = srcPtr[1]; // GrgbPtr[2] = srcPtr[0]; // Bif (hasAlpha) {uint8_t alpha = srcPtr[3];rgbPtr[3] = alpha;*smaskPtr = alpha;}else {*smaskPtr = 0xFF;}break;}default: {// 默认处理:黑色不透明rgbPtr[0] = 0;rgbPtr[1] = 0;rgbPtr[2] = 0;if (hasAlpha) {rgbPtr[3] = 0xFF;}*smaskPtr = 0xFF;break;}}
}
#endif// 设置像素数据到位图static bool SetPixelData(uint8_t* bitmapData, size_t dstOffset, int format,const std::vector<uint8_t>& rgbData, size_t rgbOffset,const std::vector<uint8_t>& smaskData, size_t smaskOffset,bool hasAlpha){switch (format) {case FXDIB_8bppMask:case FXDIB_8bppRgb:case FXDIB_8bppRgba:case FXDIB_8bppCmyk:case FXDIB_8bppCmyka: {// 8位格式处理 - 转换为灰度float gray = 0.299f * rgbData[rgbOffset] +0.587f * rgbData[rgbOffset + 1] +0.114f * rgbData[rgbOffset + 2];bitmapData[dstOffset] = static_cast<uint8_t>(gray);break;}case FXDIB_Rgb: {// 24位RGB处理bitmapData[dstOffset] = rgbData[rgbOffset + 2];     // BbitmapData[dstOffset + 1] = rgbData[rgbOffset + 1]; // GbitmapData[dstOffset + 2] = rgbData[rgbOffset];     // Rbreak;}case FXDIB_Rgba:case FXDIB_Rgb32:case FXDIB_Argb: {// 32位带Alpha处理bitmapData[dstOffset] = rgbData[rgbOffset + 2];     // BbitmapData[dstOffset + 1] = rgbData[rgbOffset + 1]; // GbitmapData[dstOffset + 2] = rgbData[rgbOffset];      // Rif (hasAlpha && rgbData.size() > rgbOffset + 3) {bitmapData[dstOffset + 3] = smaskData[smaskOffset]; // A}else {bitmapData[dstOffset + 3] = 255; // 不透明}break;}default:
#if HasDebugImagestd::cerr << "Unsupported bitmap format" << std::endl;
#endif//throw std::runtime_error("Unsupported bitmap format");return false;}}
};#include <vector>
#include <cstdint>
#include <cmath>
#include <algorithm>class ImageInterpolator {
public:// 插值方法枚举enum class Method {NEAREST_NEIGHBOR,  // 最近邻插值BILINEAR,          // 双线性插值BICUBIC            // 双三次插值};// 使用 PngManager 的 ImageData 结构(需要保持一致)struct ImageData {std::vector<uint8_t> pixels;uint32_t width = 0;uint32_t height = 0;uint8_t bitDepth = 8;};// 缩放图像方法,原地修改像素数据static bool resize(ImageData& image,uint32_t newWidth,uint32_t newHeight,Method method = Method::BILINEAR) {// 验证参数有效性if (image.pixels.empty() || image.width == 0 || image.height == 0) {return false;}if (newWidth == 0 || newHeight == 0) {return false;}// 如果目标尺寸相同则直接返回if (newWidth == image.width && newHeight == image.height) {return true;}// 只支持8位深度的图像if (image.bitDepth != 8) {return false;}// 创建目标像素缓冲区std::vector<uint8_t> resizedPixels(newWidth * newHeight * 4);for (uint32_t y = 0; y < newHeight; ++y) {for (uint32_t x = 0; x < newWidth; ++x) {// 计算原始图像中的对应位置(浮点坐标)float srcX = (x + 0.5f) * image.width / newWidth - 0.5f;float srcY = (y + 0.5f) * image.height / newHeight - 0.5f;// 边界处理srcX = (std::max)(0.0f, (std::min)(srcX, static_cast<float>(image.width - 1)));srcY = (std::max)(0.0f, (std::min)(srcY, static_cast<float>(image.height - 1)));// 对每个通道进行处理for (int c = 0; c < 4; ++c) {float value = 0.0f;switch (method) {case Method::NEAREST_NEIGHBOR:value = nearestNeighbor(srcX, srcY, c, image);break;case Method::BILINEAR:value = bilinearInterpolation(srcX, srcY, c, image);break;case Method::BICUBIC:value = bicubicInterpolation(srcX, srcY, c, image);break;}// 确保值在0-255范围内并写入目标位置resizedPixels[(y * newWidth + x) * 4 + c] =static_cast<uint8_t>((std::max)(0.0f, (std::min)(255.0f, value)));}}}// 更新图像数据image.width = newWidth;image.height = newHeight;image.pixels = std::move(resizedPixels);return true;}//返回一个新的像素数据static ImageData resizeCopy(const ImageData& source,uint32_t newWidth,uint32_t newHeight,Method method = Method::BILINEAR){// 创建目标图像数据结构ImageData result;result.width = newWidth;result.height = newHeight;result.bitDepth = source.bitDepth;//result.format = source.format;// 验证参数有效性if (source.pixels.empty() || source.width == 0 || source.height == 0) {return result; // 返回空对象}if (newWidth == 0 || newHeight == 0) {return result; // 返回空对象}// 如果目标尺寸相同则直接复制if (newWidth == source.width && newHeight == source.height) {result.pixels = source.pixels; // 复制像素数据return result;}// 只支持8位深度的图像if (source.bitDepth != 8) {return result; // 返回空对象}// 创建目标像素缓冲区result.pixels.resize(newWidth * newHeight * 4);for (uint32_t y = 0; y < newHeight; ++y) {for (uint32_t x = 0; x < newWidth; ++x) {// 计算原始图像中的对应位置(浮点坐标)float srcX = (x + 0.5f) * source.width / newWidth - 0.5f;float srcY = (y + 0.5f) * source.height / newHeight - 0.5f;// 边界处理srcX = (std::max)(0.0f, (std::min)(srcX, static_cast<float>(source.width - 1)));srcY = (std::max)(0.0f, (std::min)(srcY, static_cast<float>(source.height - 1)));// 对每个通道进行处理for (int c = 0; c < 4; ++c) {float value = 0.0f;switch (method) {case Method::NEAREST_NEIGHBOR:value = nearestNeighbor(srcX, srcY, c, source);break;case Method::BILINEAR:value = bilinearInterpolation(srcX, srcY, c, source);break;case Method::BICUBIC:value = bicubicInterpolation(srcX, srcY, c, source);break;}// 确保值在0-255范围内并写入目标位置result.pixels[(y * newWidth + x) * 4 + c] =static_cast<uint8_t>((std::max)(0.0f, (std::min)(255.0f, value)));}}}return result;}
private:// 最近邻插值static float nearestNeighbor(float srcX, float srcY, int channel, const ImageData& image) {int nearestX = static_cast<int>(std::round(srcX));int nearestY = static_cast<int>(std::round(srcY));// 边界保护nearestX = clamp(nearestX, 0, image.width - 1);nearestY = clamp(nearestY, 0, image.height - 1);return image.pixels[(nearestY * image.width + nearestX) * 4 + channel];}// 双线性插值static float bilinearInterpolation(float srcX, float srcY, int channel, const ImageData& image) {int x1 = static_cast<int>(srcX);int y1 = static_cast<int>(srcY);int x2 = (std::min)(x1 + 1, static_cast<int>(image.width - 1));int y2 = (std::min)(y1 + 1, static_cast<int>(image.height - 1));float dx = srcX - x1;float dy = srcY - y1;float v11 = image.pixels[(y1 * image.width + x1) * 4 + channel];float v21 = image.pixels[(y1 * image.width + x2) * 4 + channel];float v12 = image.pixels[(y2 * image.width + x1) * 4 + channel];float v22 = image.pixels[(y2 * image.width + x2) * 4 + channel];// 双线性插值公式return v11 * (1 - dx) * (1 - dy) +v21 * dx * (1 - dy) +v12 * (1 - dx) * dy +v22 * dx * dy;}// 双三次插值static float bicubicInterpolation(float srcX, float srcY, int channel, const ImageData& image) {int x0 = static_cast<int>(std::floor(srcX)) - 1;int y0 = static_cast<int>(std::floor(srcY)) - 1;float sum = 0.0f;float sumWeights = 0.0f;// 4x4像素采样区域for (int m = 0; m < 4; ++m) {for (int n = 0; n < 4; ++n) {int px = clamp(x0 + n, 0, image.width - 1);int py = clamp(y0 + m, 0, image.height - 1);float wx = bicubicWeight(srcX - px);float wy = bicubicWeight(srcY - py);float weight = wx * wy;sum += image.pixels[(py * image.width + px) * 4 + channel] * weight;sumWeights += weight;}}return sumWeights > 0.0f ? sum / sumWeights : 0.0f;}// 边界保护函数static int clamp(int value, int min, int max) {return (std::max)(min, (std::min)(value, max));}// 双三次插值权重计算static float bicubicWeight(float x, float a = -0.5f) {x = std::abs(x);if (x < 1.0f) {return (a + 2.0f) * x * x * x - (a + 3.0f) * x * x + 1.0f;}else if (x < 2.0f) {return a * x * x * x - 5.0f * a * x * x + 8.0f * a * x - 4.0f * a;}return 0.0f;}
};/*//int main() {
//	try {
//		// 示例1: 从位图获取图像数据
//		CFX_DIBitmap* sourceBitmap =  获取或创建位图  ;
//		auto imageData = DIBitmapConverter::GetImageData(sourceBitmap, true);
//
//		// 处理图像数据...
//		for (auto& pixel : imageData.rgbData) {
//			pixel = 255 - pixel; // 反色处理
//		}
//
//		// 示例2: 创建新位图并设置图像数据
//		auto newBitmap = DIBitmapConverter::CreateBitmapFromData(imageData, FXDIB_Rgba);
//
//		// 示例3: 修改现有位图
//		DIBitmapConverter::SetImageData(sourceBitmap, imageData);
//	}
//	catch (const std::exception& e) {
//		std::cerr << "Error: " << e.what() << std::endl;
//		return 1;
//	}
//
//	return 0;
//}
//*/
#include <vector>
#include <cstdint>
//#include <png.h>
#include <functional>class PngManager {
public:// 错误码枚举enum class ErrorCode {Success = 0,CreateReadStructFailed,CreateInfoStructFailed,CreateWriteStructFailed,PngProcessingError,UnsupportedFormat,InvalidParameters,MemoryAllocationFailed};// 像素格式enum class PixelFormat {Grayscale = PNG_COLOR_TYPE_GRAY,RGB = PNG_COLOR_TYPE_RGB,RGBA = PNG_COLOR_TYPE_RGBA,GrayscaleAlpha = PNG_COLOR_TYPE_GRAY_ALPHA,Palette = PNG_COLOR_TYPE_PALETTE};// 图像数据结构struct ImageData {std::vector<uint8_t> pixels;uint32_t width = 0;uint32_t height = 0;PixelFormat format = PixelFormat::RGBA;uint8_t bitDepth = 8;};// 分离的RGB和Alpha通道struct SeparatedChannels {std::vector<uint8_t> rgbData;std::vector<uint8_t> alphaData;uint32_t width = 0;uint32_t height = 0;};// 构造函数/析构函数PngManager() = default;~PngManager() = default;// 从内存读取PNGErrorCode ReadFromMemory(const uint8_t* buffer, size_t size, ImageData& outImage) {if (!buffer || size == 0) {return ErrorCode::InvalidParameters;}// 初始化读取结构png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);if (!pngPtr) {return ErrorCode::CreateReadStructFailed;}png_infop infoPtr = png_create_info_struct(pngPtr);if (!infoPtr) {png_destroy_read_struct(&pngPtr, nullptr, nullptr);return ErrorCode::CreateInfoStructFailed;}// 错误处理设置if (setjmp(png_jmpbuf(pngPtr))) {png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);return ErrorCode::PngProcessingError;}// 设置内存读取回调struct ReadContext {const uint8_t* data;size_t pos;} ctx{ buffer, 0 };png_set_read_fn(pngPtr, &ctx, [](png_structp pngPtr, png_bytep data, png_size_t length) {auto* ctx = static_cast<ReadContext*>(png_get_io_ptr(pngPtr));memcpy(data, ctx->data + ctx->pos, length);ctx->pos += length;});// 读取PNG信息png_read_info(pngPtr, infoPtr);// 获取基本信息outImage.width = png_get_image_width(pngPtr, infoPtr);outImage.height = png_get_image_height(pngPtr, infoPtr);outImage.format = static_cast<PixelFormat>(png_get_color_type(pngPtr, infoPtr));outImage.bitDepth = png_get_bit_depth(pngPtr, infoPtr);// 格式转换处理if (outImage.bitDepth == 16) {png_set_strip_16(pngPtr);outImage.bitDepth = 8;}if (outImage.format == PixelFormat::Palette) {png_set_palette_to_rgb(pngPtr);}if (outImage.format == PixelFormat::Grayscale && outImage.bitDepth < 8) {png_set_expand_gray_1_2_4_to_8(pngPtr);}if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) {png_set_tRNS_to_alpha(pngPtr);}if (outImage.format == PixelFormat::RGB ||outImage.format == PixelFormat::Grayscale ||outImage.format == PixelFormat::Palette) {png_set_add_alpha(pngPtr, 0xFF, PNG_FILLER_AFTER);}// 更新信息png_read_update_info(pngPtr, infoPtr);outImage.format = static_cast<PixelFormat>(png_get_color_type(pngPtr, infoPtr));outImage.bitDepth = png_get_bit_depth(pngPtr, infoPtr);// 分配内存并读取图像png_size_t rowBytes = png_get_rowbytes(pngPtr, infoPtr);outImage.pixels.resize(rowBytes * outImage.height);std::vector<png_bytep> rowPointers(outImage.height);for (uint32_t y = 0; y < outImage.height; ++y) {rowPointers[y] = outImage.pixels.data() + y * rowBytes;}png_read_image(pngPtr, rowPointers.data());png_read_end(pngPtr, nullptr);png_destroy_read_struct(&pngPtr, &infoPtr, nullptr);return ErrorCode::Success;}// 写入PNG到内存ErrorCode WriteToMemory(const ImageData& image, std::vector<uint8_t>& outBuffer, int compressionLevel = 6) {if (image.pixels.empty() || image.width == 0 || image.height == 0) {return ErrorCode::InvalidParameters;}// 初始化写入结构png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);if (!pngPtr) {return ErrorCode::CreateWriteStructFailed;}png_infop infoPtr = png_create_info_struct(pngPtr);if (!infoPtr) {png_destroy_write_struct(&pngPtr, nullptr);return ErrorCode::CreateInfoStructFailed;}// 错误处理设置if (setjmp(png_jmpbuf(pngPtr))) {png_destroy_write_struct(&pngPtr, &infoPtr);return 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);// 设置PNG头信息png_set_IHDR(pngPtr, infoPtr, image.width, image.height,image.bitDepth, static_cast<int>(image.format),PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);// 准备行指针png_size_t rowBytes = png_get_rowbytes(pngPtr, infoPtr);std::vector<png_bytep> rowPointers(image.height);for (uint32_t y = 0; y < image.height; ++y) {rowPointers[y] = const_cast<uint8_t*>(image.pixels.data()) + y * rowBytes;}// 写入数据png_write_info(pngPtr, infoPtr);png_write_image(pngPtr, rowPointers.data());png_write_end(pngPtr, nullptr);png_destroy_write_struct(&pngPtr, &infoPtr);return ErrorCode::Success;}// 分离RGB和Alpha通道ErrorCode SeparateChannels(const ImageData& image, SeparatedChannels& outChannels) {if (image.pixels.empty() || image.width == 0 || image.height == 0) {return ErrorCode::InvalidParameters;}outChannels.width = image.width;outChannels.height = image.height;switch (image.format) {case PixelFormat::RGBA: {// RGBA格式: RGB和Alpha分离size_t pixelCount = image.width * image.height;outChannels.rgbData.resize(pixelCount * 3);outChannels.alphaData.resize(pixelCount);for (size_t i = 0; i < pixelCount; ++i) {outChannels.rgbData[i * 3] = image.pixels[i * 4];outChannels.rgbData[i * 3 + 1] = image.pixels[i * 4 + 1];outChannels.rgbData[i * 3 + 2] = image.pixels[i * 4 + 2];outChannels.alphaData[i] = image.pixels[i * 4 + 3];}break;}case PixelFormat::GrayscaleAlpha: {// 灰度+Alpha: 转换为RGB+Alphasize_t pixelCount = image.width * image.height;outChannels.rgbData.resize(pixelCount * 3);outChannels.alphaData.resize(pixelCount);for (size_t i = 0; i < pixelCount; ++i) {uint8_t gray = image.pixels[i * 2];outChannels.rgbData[i * 3] = gray;outChannels.rgbData[i * 3 + 1] = gray;outChannels.rgbData[i * 3 + 2] = gray;outChannels.alphaData[i] = image.pixels[i * 2 + 1];}break;}case PixelFormat::RGB:case PixelFormat::Grayscale: {// 无Alpha通道: 只提取RGB/灰度数据size_t pixelCount = image.width * image.height;if (image.format == PixelFormat::Grayscale) {// 灰度转RGBoutChannels.rgbData.resize(pixelCount * 3);for (size_t i = 0; i < pixelCount; ++i) {uint8_t gray = image.pixels[i];outChannels.rgbData[i * 3] = gray;outChannels.rgbData[i * 3 + 1] = gray;outChannels.rgbData[i * 3 + 2] = gray;}}else {// 直接复制RGB数据outChannels.rgbData = image.pixels;}// Alpha通道为空outChannels.alphaData.clear();break;}default:return ErrorCode::UnsupportedFormat;}return ErrorCode::Success;}// 合并RGB和Alpha通道ErrorCode MergeChannels(const SeparatedChannels& channels, ImageData& outImage, PixelFormat format = PixelFormat::RGBA) {if (channels.rgbData.empty() || channels.width == 0 || channels.height == 0) {return ErrorCode::InvalidParameters;}outImage.width = channels.width;outImage.height = channels.height;outImage.format = format;outImage.bitDepth = 8;size_t pixelCount = channels.width * channels.height;bool hasAlpha = !channels.alphaData.empty();// 检查输入数据有效性if (channels.rgbData.size() != pixelCount * 3) {return ErrorCode::InvalidParameters;}if (hasAlpha && channels.alphaData.size() != pixelCount) {return ErrorCode::InvalidParameters;}// 根据输出格式分配内存switch (format) {case PixelFormat::RGBA: {outImage.pixels.resize(pixelCount * 4);for (size_t i = 0; i < pixelCount; ++i) {outImage.pixels[i * 4] = channels.rgbData[i * 3];     // RoutImage.pixels[i * 4 + 1] = channels.rgbData[i * 3 + 1]; // GoutImage.pixels[i * 4 + 2] = channels.rgbData[i * 3 + 2]; // BoutImage.pixels[i * 4 + 3] = hasAlpha ? channels.alphaData[i] : 0xFF; // A}break;}case PixelFormat::GrayscaleAlpha: {outImage.pixels.resize(pixelCount * 2);for (size_t i = 0; i < pixelCount; ++i) {// 转换为灰度: 0.299R + 0.587G + 0.114Bfloat gray = 0.299f * channels.rgbData[i * 3] +0.587f * channels.rgbData[i * 3 + 1] +0.114f * channels.rgbData[i * 3 + 2];outImage.pixels[i * 2] = static_cast<uint8_t>(gray);outImage.pixels[i * 2 + 1] = hasAlpha ? channels.alphaData[i] : 0xFF;}break;}case PixelFormat::RGB: {outImage.pixels = channels.rgbData;break;}case PixelFormat::Grayscale: {outImage.pixels.resize(pixelCount);for (size_t i = 0; i < pixelCount; ++i) {// 转换为灰度float gray = 0.299f * channels.rgbData[i * 3] +0.587f * channels.rgbData[i * 3 + 1] +0.114f * channels.rgbData[i * 3 + 2];outImage.pixels[i] = static_cast<uint8_t>(gray);}break;}default:return ErrorCode::UnsupportedFormat;}return ErrorCode::Success;}//补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充 //补充// 为我增加函数,将分离出的像素数据和smask 分别导出// 将分离的RGB通道导出为PNGErrorCode ExportRgbToMemory(const SeparatedChannels& separated, std::vector<uint8_t>& outBuffer, int compressionLevel = 6) {if (separated.rgbData.empty() || separated.width == 0 || separated.height == 0) {return ErrorCode::InvalidParameters;}// 创建RGB图像数据ImageData rgbImage;rgbImage.width = separated.width;rgbImage.height = separated.height;rgbImage.format = PixelFormat::RGB;rgbImage.bitDepth = 8;rgbImage.pixels = separated.rgbData;// 写入内存return WriteToMemory(rgbImage, outBuffer, compressionLevel);}// 将分离的Alpha通道(smask)导出为PNGErrorCode ExportSmaskToMemory(const SeparatedChannels& separated, std::vector<uint8_t>& outBuffer, int compressionLevel = 6) {if (separated.alphaData.empty() || separated.width == 0 || separated.height == 0) {return ErrorCode::InvalidParameters;}// 创建灰度图像数据(8位)ImageData smaskImage;smaskImage.width = separated.width;smaskImage.height = separated.height;smaskImage.format = PixelFormat::Grayscale;smaskImage.bitDepth = 8;smaskImage.pixels = separated.alphaData;// 写入内存return WriteToMemory(smaskImage, outBuffer, compressionLevel);}// 将分离的通道分别导出到两个内存缓冲区ErrorCode ExportSeparatedChannels(const SeparatedChannels& separated,std::vector<uint8_t>& outRgbBuffer,std::vector<uint8_t>& outSmaskBuffer,int compressionLevel = 6) {auto err = ExportRgbToMemory(separated, outRgbBuffer, compressionLevel);if (err != ErrorCode::Success) {return err;}// 只有存在alpha数据时才导出smaskif (!separated.alphaData.empty()) {err = ExportSmaskToMemory(separated, outSmaskBuffer, compressionLevel);if (err != ErrorCode::Success) {return err;}}return ErrorCode::Success;}//补充结束//补充结束//补充结束//补充结束//补充结束//补充结束//补充结束//补充结束//补充结束//补充结束#if 1//HasPDFCore// 导出包含smask的标准PNG(RGBA格式)ErrorCode ExportPngWithSmask(const DIBitmapConverter::ImageData& dibData,std::vector<uint8_t>& outPng,int compressionLevel = 6) {// 验证输入数据if (dibData.rgbData.empty() || dibData.width == 0 || dibData.height == 0) {return ErrorCode::InvalidParameters;}// 检查RGB数据大小是否匹配bool hasAlphaInRgb = dibData.rgbData.size() == dibData.width * dibData.height * 4;bool hasNoAlphaInRgb = dibData.rgbData.size() == dibData.width * dibData.height * 3;if (!hasAlphaInRgb && !hasNoAlphaInRgb) {return ErrorCode::InvalidParameters;}// 检查smask数据大小是否匹配(如果有alpha)if (dibData.hasAlpha && !dibData.smaskData.empty()) {if (dibData.smaskData.size() < dibData.width * dibData.height) {return ErrorCode::InvalidParameters;}}// 初始化PNG写入结构png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);if (!png_ptr) {return ErrorCode::CreateWriteStructFailed;}png_infop info_ptr = png_create_info_struct(png_ptr);if (!info_ptr) {png_destroy_write_struct(&png_ptr, nullptr);return ErrorCode::CreateInfoStructFailed;}// 错误处理设置if (setjmp(png_jmpbuf(png_ptr))) {png_destroy_write_struct(&png_ptr, &info_ptr);return ErrorCode::PngProcessingError;}// 自定义写入函数struct PngWriteBuffer {std::vector<uint8_t>* buffer;size_t pos;};PngWriteBuffer write_buffer = { &outPng, 0 };auto write_data = [](png_structp png_ptr, png_bytep data, png_size_t length) {PngWriteBuffer* buffer = static_cast<PngWriteBuffer*>(png_get_io_ptr(png_ptr));buffer->buffer->resize(buffer->pos + length);memcpy(&((*buffer->buffer)[buffer->pos]), data, length);buffer->pos += length;};auto flush_data = [](png_structp png_ptr) {};png_set_write_fn(png_ptr, &write_buffer, write_data, flush_data);// 设置压缩级别png_set_compression_level(png_ptr, compressionLevel);// 设置PNG头信息png_set_IHDR(png_ptr, info_ptr, dibData.width, dibData.height,8, PNG_COLOR_TYPE_RGBA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);// 准备行指针数组std::vector<png_bytep> row_pointers(dibData.height);std::vector<uint8_t> rgbaData(dibData.width * dibData.height * 4);// 根据GetImageData的提取方式填充RGBA数据if (hasAlphaInRgb) {// 如果rgbData已经是RGBA格式(4通道)for (uint32_t y = 0; y < dibData.height; ++y) {for (uint32_t x = 0; x < dibData.width; ++x) {size_t srcOffset = (y * dibData.width + x) * 4;size_t dstOffset = (y * dibData.width + x) * 4;// 直接复制RGB数据rgbaData[dstOffset] = dibData.rgbData[srcOffset];     // RrgbaData[dstOffset + 1] = dibData.rgbData[srcOffset + 1]; // GrgbaData[dstOffset + 2] = dibData.rgbData[srcOffset + 2]; // B// 使用rgbData中的Alpha或smaskData中的Alphaif (dibData.hasAlpha && !dibData.smaskData.empty()) {rgbaData[dstOffset + 3] = dibData.smaskData[y * dibData.width + x]; // A}else {rgbaData[dstOffset + 3] = dibData.rgbData[srcOffset + 3]; // A}}}}else {// 如果rgbData是RGB格式(3通道)for (uint32_t y = 0; y < dibData.height; ++y) {for (uint32_t x = 0; x < dibData.width; ++x) {size_t srcOffset = (y * dibData.width + x) * 3;size_t dstOffset = (y * dibData.width + x) * 4;// 复制RGB数据rgbaData[dstOffset] = dibData.rgbData[srcOffset];     // RrgbaData[dstOffset + 1] = dibData.rgbData[srcOffset + 1]; // GrgbaData[dstOffset + 2] = dibData.rgbData[srcOffset + 2]; // B// 设置Alpha通道if (dibData.hasAlpha && !dibData.smaskData.empty()) {rgbaData[dstOffset + 3] = dibData.smaskData[y * dibData.width + x]; // A}else {rgbaData[dstOffset + 3] = 0xFF; // 不透明}}}}// 设置行指针for (uint32_t y = 0; y < dibData.height; ++y) {row_pointers[y] = rgbaData.data() + y * dibData.width * 4;}// 写入PNG数据png_write_info(png_ptr, info_ptr);png_write_image(png_ptr, row_pointers.data());png_write_end(png_ptr, nullptr);// 清理资源png_destroy_write_struct(&png_ptr, &info_ptr);return ErrorCode::Success;}//单独导出 RGB 数据(不含 Alpha)​ErrorCode ExportRgbDataToPng(const DIBitmapConverter::ImageData& dibData,std::vector<uint8_t>& outRgbPng,int compressionLevel = 6) {// 验证输入数据if (dibData.rgbData.empty() || dibData.width == 0 || dibData.height == 0) {return ErrorCode::InvalidParameters;}// 检查RGB数据是否完整(必须至少包含3通道数据)size_t requiredSize = dibData.width * dibData.height * 3;if (dibData.rgbData.size() < requiredSize) {return ErrorCode::InvalidParameters;}// 初始化PNGpng_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);if (!png_ptr) return ErrorCode::CreateWriteStructFailed;png_infop info_ptr = png_create_info_struct(png_ptr);if (!info_ptr) {png_destroy_write_struct(&png_ptr, nullptr);return ErrorCode::CreateInfoStructFailed;}if (setjmp(png_jmpbuf(png_ptr))) {png_destroy_write_struct(&png_ptr, &info_ptr);return ErrorCode::PngProcessingError;}// 内存写入回调struct WriteContext {std::vector<uint8_t>* buffer;size_t offset = 0;} ctx{ &outRgbPng };png_set_write_fn(png_ptr, &ctx, [](png_structp png, png_bytep data, png_size_t len) {auto* c = static_cast<WriteContext*>(png_get_io_ptr(png));c->buffer->resize(c->offset + len);memcpy(c->buffer->data() + c->offset, data, len);c->offset += len;}, nullptr);// 设置压缩和PNG头(强制输出为RGB格式)png_set_compression_level(png_ptr, compressionLevel);png_set_IHDR(png_ptr, info_ptr, dibData.width, dibData.height,8, PNG_COLOR_TYPE_RGB,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);// 准备行指针std::vector<png_bytep> row_pointers(dibData.height);std::vector<uint8_t> contiguous_rgb_data; // 连续存储的RGB数据// 关键修正:统一处理3/4通道输入数据if (dibData.hasAlpha && dibData.rgbData.size() >= dibData.width * dibData.height * 4) {// 从RGBA数据中提取RGBcontiguous_rgb_data.resize(dibData.width * dibData.height * 3);for (uint32_t i = 0; i < dibData.width * dibData.height; ++i) {contiguous_rgb_data[i * 3] = dibData.rgbData[i * 4];     // Rcontiguous_rgb_data[i * 3 + 1] = dibData.rgbData[i * 4 + 1];   // Gcontiguous_rgb_data[i * 3 + 2] = dibData.rgbData[i * 4 + 2];   // B}}else {// 直接使用RGB数据(确保数据连续)contiguous_rgb_data = dibData.rgbData;}// 设置行指针(每行width*3字节)for (uint32_t y = 0; y < dibData.height; ++y) {row_pointers[y] = contiguous_rgb_data.data() + y * dibData.width * 3;}// 写入数据png_write_info(png_ptr, info_ptr);png_write_image(png_ptr, row_pointers.data());png_write_end(png_ptr, nullptr);// 清理png_destroy_write_struct(&png_ptr, &info_ptr);return ErrorCode::Success;}//单独导出 smask (Alpha) 数据​ErrorCode ExportSmaskToPng(const DIBitmapConverter::ImageData& dibData,std::vector<uint8_t>& outSmaskPng,int compressionLevel = 6) {// 验证输入if (!dibData.hasAlpha || dibData.smaskData.empty() ||dibData.width == 0 || dibData.height == 0) {return ErrorCode::InvalidParameters;}// 检查Alpha数据大小if (dibData.smaskData.size() < dibData.width * dibData.height) {return ErrorCode::InvalidParameters;}// 初始化PNGpng_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);if (!png_ptr) return ErrorCode::CreateWriteStructFailed;png_infop info_ptr = png_create_info_struct(png_ptr);if (!info_ptr) {png_destroy_write_struct(&png_ptr, nullptr);return ErrorCode::CreateInfoStructFailed;}if (setjmp(png_jmpbuf(png_ptr))) {png_destroy_write_struct(&png_ptr, &info_ptr);return ErrorCode::PngProcessingError;}// 内存写入回调struct WriteContext {std::vector<uint8_t>* buffer;size_t offset = 0;} ctx{ &outSmaskPng };png_set_write_fn(png_ptr, &ctx, [](png_structp png, png_bytep data, png_size_t len) {auto* c = static_cast<WriteContext*>(png_get_io_ptr(png));c->buffer->resize(c->offset + len);memcpy(c->buffer->data() + c->offset, data, len);c->offset += len;}, nullptr);// 设置压缩和PNG头(灰度图)png_set_compression_level(png_ptr, compressionLevel);png_set_IHDR(png_ptr, info_ptr, dibData.width, dibData.height,8, PNG_COLOR_TYPE_GRAY,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);// 准备行指针std::vector<png_bytep> row_pointers(dibData.height);for (uint32_t y = 0; y < dibData.height; ++y) {row_pointers[y] = const_cast<uint8_t*>(dibData.smaskData.data()) + y * dibData.width;}// 写入数据png_write_info(png_ptr, info_ptr);png_write_image(png_ptr, row_pointers.data());png_write_end(png_ptr, nullptr);// 清理png_destroy_write_struct(&png_ptr, &info_ptr);return ErrorCode::Success;}//统一导出 rgb 和 smask 图像数据ErrorCode ExportSeparatedChannels(const DIBitmapConverter::ImageData& dibData,std::vector<uint8_t>& outRgbPng,std::vector<uint8_t>& outSmaskPng,int compressionLevel = 6) {// 导出RGBauto err = ExportRgbDataToPng(dibData, outRgbPng, compressionLevel);if (err != ErrorCode::Success) return err;// 仅当存在Alpha时导出smaskif (dibData.hasAlpha && !dibData.smaskData.empty()) {err = ExportSmaskToPng(dibData, outSmaskPng, compressionLevel);}return err;}void ExtractImageDataFromDIBitmap(CFX_DIBitmap* sourceBitmap,PngManager::ImageData& imageData){// 使用DIBitmapConverter提取图像数据DIBitmapConverter::ImageData convertedData =DIBitmapConverter::GetImageData(sourceBitmap, true);// 设置基本图像属性imageData.width = convertedData.width;imageData.height = convertedData.height;imageData.bitDepth = 8; // 假设8位深度imageData.format = PngManager::PixelFormat::RGBA; // 设置为RGBA格式// 判断是否有Alpha通道const bool hasAlpha = !convertedData.smaskData.empty() &&convertedData.smaskData.size() >= convertedData.width * convertedData.height;// 合并RGB和Alpha到RGBA格式const size_t pixelCount = convertedData.width * convertedData.height;imageData.pixels.resize(pixelCount * 4); // 为RGBA格式分配空间// 复制RGB和Alpha数据for (size_t i = 0; i < pixelCount; i++) {const size_t rgbOffset = hasAlpha ? i * 4 : i * 3;const size_t rgbaOffset = i * 4;// 复制RGB数据if (convertedData.rgbData.size() > rgbOffset + 2) {imageData.pixels[rgbaOffset] = convertedData.rgbData[rgbOffset];     // RimageData.pixels[rgbaOffset + 1] = convertedData.rgbData[rgbOffset + 1]; // GimageData.pixels[rgbaOffset + 2] = convertedData.rgbData[rgbOffset + 2]; // B}else {// 如果RGB数据不完整,使用黑色imageData.pixels[rgbaOffset] = 0;imageData.pixels[rgbaOffset + 1] = 0;imageData.pixels[rgbaOffset + 2] = 0;}// 设置Alpha通道if (hasAlpha && convertedData.smaskData.size() > i) {imageData.pixels[rgbaOffset + 3] = convertedData.smaskData[i]; // A}else {imageData.pixels[rgbaOffset + 3] = 0xFF; // 不透明}}}
#endifprivate:// 禁用拷贝和赋值PngManager(const PngManager&) = delete;PngManager& operator=(const PngManager&) = delete;
};#include <vector>
#include <cmath>
#include <algorithm>
#include <stdexcept>///*
//
//PngManager pngManager; // 只需初始化一次
//
 多次读取不同文件
//auto image1 = pngManager.readPng("image1.png");
//auto image2 = pngManager.readPng("image2.png");
//
 多次写入不同文件
//pngManager.writePng("output1.png", image1);
//pngManager.writePng("output2.png", image2);
//
//*/
//
///*
//int main() {
//	try {
//		// 原始图像数据 (假设已加载)
//		ImageData originalImage;
//		originalImage.width = 1920;
//		originalImage.height = 1080;
//		originalImage.pixels.resize(1920 * 1080 * 4); // RGBA格式
//
//		// 使用双线性插值缩放图像到800x600
//		ImageResizer::resize(originalImage, 800, 600,
//						   ImageResizer::InterpolationMethod::BILINEAR);
//
//		// 使用双三次插值缩放图像到400x300
//		ImageResizer::resize(originalImage, 400, 300,
//						   ImageResizer::InterpolationMethod::BICUBIC);
//
//		// 使用最近邻插值缩放图像到200x150
//		ImageResizer::resize(originalImage, 200, 150,
//						   ImageResizer::InterpolationMethod::NEAREST_NEIGHBOR);
//	} catch (const std::exception& e) {
//		std::cerr << "图像缩放错误: " << e.what() << std::endl;
//		return 1;
//	}
//
//	return 0;
//}
//*/
//
///*
//int main() {
//	try {
//		PngManager pngManager;
//
//		// 方法1: 读取后分离
//		auto image = pngManager.readPng("input.png");
//		auto separated = pngManager.separateSmask(image);
//
//		// 保存分离的数据
//		pngManager.writeSeparatedSmask("output_rgb.png", "output_smask.png", separated);
//
//		// 方法2: 直接读取并分离
//		auto separated2 = pngManager.readAndSeparateSmask("input2.png");
//
//		// 修改smask数据 (例如阈值处理)
//		for (auto& alpha : separated2.smaskData) {
//			alpha = alpha > 128 ? 255 : 0; // 二值化处理
//		}
//
//		// 重新合并并保存
//		auto combined = pngManager.combineSmask(separated2);
//		pngManager.writePng("output_modified.png", combined);
//	} catch (const PngException& e) {
//		std::cerr << "PNG处理错误: " << e.what() << std::endl;
//		return 1;
//	}
//
//	return 0;
//}
//*/
//
///*
//int main() {
//	try {
//		PngManager pngManager;
//
//		// 1. 读取并分离图像
//		auto separated = pngManager.readAndSeparateSmask("input.png");
//
//		// 2. 对分离数据进行处理 (示例:将smask二值化)
//		for (auto& alpha : separated.smaskData) {
//			alpha = alpha > 128 ? 255 : 0;
//		}
//
//		// 3. 重新合并为完整图像 (RGBA格式)
//		auto mergedImage = pngManager.mergeSmaskAndRgb(separated);
//		pngManager.writePng("output_rgba.png", mergedImage);
//
//		// 4. 直接合并并保存为灰度+Alpha格式
//		pngManager.writeMergedImage("output_gray_alpha.png", separated,
//								   PngManager::PixelFormat::GRAYSCALE_ALPHA);
//
//		// 5. 合并为RGB格式 (无Alpha通道)
//		pngManager.writeMergedImage("output_rgb.png", separated,
//								  PngManager::PixelFormat::RGB);
//	} catch (const PngException& e) {
//		std::cerr << "PNG处理错误: " << e.what() << std::endl;
//		return 1;
//	}
//
//	return 0;
//}
//*/
//
//#include <vector>
//#include <cassert>
//#include <memory>//class PDFCorePngManager //这个类负责向外暴露函数,因为pdfcore 那层缺少png相关的头文件void PDFCorePngManager::ExtractPngDataFromDIBitmap(CFX_DIBitmap* sourceBitmap, std::vector<uint8_t>& png_data)
{auto imageData = DIBitmapConverter::GetImageData(sourceBitmap, true);PngManager png_manager;png_manager.ExportPngWithSmask(imageData, png_data);//WriteVectorToFile(rgb_image_data, "D:/New_Code/UtilityCode/TestPDFCore/test_pdfcore/pdfcore_rgb.png");//WriteVectorToFile(smask_image_data, "D:/New_Code/UtilityCode/TestPDFCore/test_pdfcore/pdfcore_smask.png");
}
void PDFCorePngManager::ExtractSmaskDataFromDIBitmap(CFX_DIBitmap* sourceBitmap, std::vector<uint8_t>& smask_image_data)
{auto imageData = DIBitmapConverter::GetImageData(sourceBitmap, true);PngManager png_manager;png_manager.ExportSmaskToPng(imageData, smask_image_data);
}
void PDFCorePngManager::ExtractRgbDataFromDIBitmap(CFX_DIBitmap* sourceBitmap, std::vector<uint8_t>& rgb_image_data)
{auto imageData = DIBitmapConverter::GetImageData(sourceBitmap, true);PngManager png_manager;png_manager.ExportRgbDataToPng(imageData, rgb_image_data);
}
void PDFCorePngManager::ExtractRgbSmaskDataFromDIBitmap(CFX_DIBitmap* sourceBitmap, std::vector<uint8_t>& rgb_image_data, std::vector<uint8_t>& smask_image_data)
{auto imageData = DIBitmapConverter::GetImageData(sourceBitmap, true);PngManager png_manager;png_manager.ExportSeparatedChannels(imageData, rgb_image_data, smask_image_data);
}/*** 将 std::vector<uint8_t> 写入指定文件* @param data 要写入的数据向量* @param filename 目标文件名* @return 成功返回true,失败返回false*/
bool PDFCorePngManager::WriteVectorToFile(const std::vector<uint8_t>& data, const std::string& filename) {// 以二进制模式打开文件,截断方式写入std::ofstream outfile(filename, std::ios::binary | std::ios::trunc);if (!outfile.is_open()) {return false; // 文件打开失败}// 写入数据outfile.write(reinterpret_cast<const char*>(data.data()), data.size());// 检查是否写入成功if (!outfile.good()) {outfile.close();return false;}outfile.close();return true;
}/*** 从指定文件读取数据到 std::vector<uint8_t>* @param data 读取的数据将存储在此向量中* @param filename 要读取的文件名* @return 成功返回true,失败返回false*/
bool static ReadVectorFromFile(std::vector<uint8_t>& data, const std::string& filename) {// 清空数据向量,准备接收新数据data.clear();// 以二进制模式打开文件std::ifstream infile(filename, std::ios::binary);if (!infile.is_open()) {return false; // 文件打开失败}// 获取文件大小infile.seekg(0, std::ios::end);std::streamsize size = infile.tellg();infile.seekg(0, std::ios::beg);if (size == -1) {// 获取文件大小失败infile.close();return false;}// 预分配向量内存空间data.reserve(static_cast<size_t>(size));// 读取文件内容到向量data.assign(std::istreambuf_iterator<char>(infile), std::istreambuf_iterator<char>());// 检查是否读取成功if (!infile.good()) {infile.close();return false;}infile.close();return true;
}
// 实现插值方法映射
ImageInterpolator::Method static MapInterpolationMethod(PDFCorePngManager::PDFCoreInterpolationMethod foxitMethod)
{switch (foxitMethod) {case PDFCorePngManager::PDFCoreInterpolationMethod::BICUBIC:return ImageInterpolator::Method::BICUBIC;case PDFCorePngManager::PDFCoreInterpolationMethod::BILINEAR:return ImageInterpolator::Method::BILINEAR;case PDFCorePngManager::PDFCoreInterpolationMethod::NEAREST_NEIGHBOR:default:return ImageInterpolator::Method::NEAREST_NEIGHBOR;}
}// 实现图像像素数据缩放
bool static ResizeImageData(const PngManager::ImageData& source,PngManager::ImageData& target,ImageInterpolator::Method method)
{// 创建输入图像数据结构ImageInterpolator::ImageData input;input.width = source.width;input.height = source.height;input.bitDepth = source.bitDepth;input.pixels = source.pixels; // 共享数据// 创建输出图像数据结构ImageInterpolator::ImageData output;output.width = target.width;output.height = target.height;output.bitDepth = target.bitDepth;output.pixels.resize(target.width * target.height * 4); // 预分配空间// 执行缩放output = ImageInterpolator::resizeCopy(input, target.width, target.height, method);// 移动数据到目标target.pixels = std::move(output.pixels);return true;
}// 实现ResizeImage方法
std::vector<uint8_t> PDFCorePngManager::ResizeImage(CFX_DIBitmap* sourceBitmap,PDFCoreInterpolationMethod pdfore_interpolation_method,int WidthScaleFactor)
{// 验证输入参数if (!sourceBitmap || WidthScaleFactor <= 0) {return {};}// 直接从源位图提取图像数据,这个是像素数据,不是编码之后的图像数据PngManager::ImageData sourceImage;PngManager png_manager;png_manager.ExtractImageDataFromDIBitmap(sourceBitmap, sourceImage);// 验证图像数据if (sourceImage.pixels.empty() || sourceImage.width == 0 || sourceImage.height == 0) {return {};}// 计算目标尺寸uint32_t targetWidth = (std::max)(1, static_cast<int>(sourceImage.width) / WidthScaleFactor);uint32_t targetHeight = (std::max)(1, static_cast<int>(sourceImage.height) / WidthScaleFactor);// 映射插值方法ImageInterpolator::Method interpolationMethod =MapInterpolationMethod(pdfore_interpolation_method);// 准备目标图像数据结构PngManager::ImageData targetImage;targetImage.width = targetWidth;targetImage.height = targetHeight;targetImage.bitDepth = sourceImage.bitDepth;targetImage.format = sourceImage.format;// 执行缩放if (!ResizeImageData(sourceImage, targetImage, interpolationMethod)) {return {};}// 将缩放后的图像像素数据编码为PNGstd::vector<uint8_t> outputPng;PngManager pngManager;if (pngManager.WriteToMemory(targetImage, outputPng) != PngManager::ErrorCode::Success) {return {};}return outputPng;
}

头文件


/*** @class PDFCorePngManager* @brief 对 PngWrap 的升级版本,用于从 CFX_DIBitmap 中提取并且转换为 PNG 相关数据* @note Maintained by sylar ding. Do not modify without permission*/
class PDFCorePngManager
{
public:// 插值方法枚举enum class PDFCoreInterpolationMethod {NEAREST_NEIGHBOR,  // 最近邻插值BILINEAR,          // 双线性插值BICUBIC            // 双三次插值};
public:// 构造函数/析构函数PDFCorePngManager() = default;~PDFCorePngManager() = default;/*** @brief 从 CFX_DIBitmap 中提取完整的 PNG 图像数据(包含 RGB 和 Alpha 通道)* @param sourceBitmap 输入的位图数据* @param png_data 输出的 PNG 图像数据*/void ExtractPngDataFromDIBitmap(CFX_DIBitmap* sourceBitmap,std::vector<uint8_t>& png_data);/*** @brief 从 CFX_DIBitmap 中单独提取 smask(Alpha 通道)的 PNG 图像数据* @param sourceBitmap 输入的位图数据* @param smask_image_data 输出的 smask PNG 图像数据*/void ExtractSmaskDataFromDIBitmap(CFX_DIBitmap* sourceBitmap,std::vector<uint8_t>& smask_image_data);/*** @brief 从 CFX_DIBitmap 中单独提取 RGB(不含 Alpha)的 PNG 图像数据* @param sourceBitmap 输入的位图数据* @param rgb_image_data 输出的 RGB PNG 图像数据*/void ExtractRgbDataFromDIBitmap(CFX_DIBitmap* sourceBitmap,std::vector<uint8_t>& rgb_image_data);/*** @brief 从 CFX_DIBitmap 中同时提取 RGB 和 smask 的 PNG 图像数据* @param sourceBitmap 输入的位图数据* @param rgb_image_data 输出的 RGB PNG 图像数据* @param smask_image_data 输出的 smask PNG 图像数据*/void ExtractRgbSmaskDataFromDIBitmap(CFX_DIBitmap* sourceBitmap,std::vector<uint8_t>& rgb_image_data,std::vector<uint8_t>& smask_image_data);/*** 将 std::vector<uint8_t> 写入指定文件* @param data 要写入的数据向量* @param filename 目标文件名* @return 成功返回true,失败返回false*/bool WriteVectorToFile(const std::vector<uint8_t>& data, const std::string& filename);/*** @brief 缩放图像并生成PNG数据* @param sourceBitmap 输入图像位图(必须非空)* @param interpolation_method 缩放算法,默认最近邻* @param WidthScaleFactor 宽度缩放倍数,默认5倍* @return 缩放后的PNG数据* @note 缩放会保持宽高比,高度按宽度比例自动调整*/std::vector<uint8_t> ResizeImage(CFX_DIBitmap* sourceBitmap,PDFCoreInterpolationMethod interpolation_method = PDFCoreInterpolationMethod::NEAREST_NEIGHBOR,int WidthScaleFactor = 5);
private:// 禁用拷贝和赋值PDFCorePngManager(const PDFCorePngManager&) = delete;PDFCorePngManager& operator=(const PDFCorePngManager&) = delete;
};
#endif
http://www.dtcms.com/a/266190.html

相关文章:

  • 译码器Multisim电路仿真汇总——硬件工程师笔记
  • 嵌入式系统中实现串口重定向
  • 【模糊集合】示例
  • 【MySQL\Oracle\PostgreSQL】迁移到openGauss数据出现的问题解决方案
  • Qt Creator自定义控件开发流程
  • redis缓存三大问题分析与解决方案
  • 车载以太网都有什么协议?
  • 创建 TransactionStatus
  • 【STM32实践篇】:I2C驱动编写
  • NumPy 安装使用教程
  • Debian-10-standard用`networking`服务的`/etc/network/interfaces`配置文件设置多网卡多IPv6
  • 【2.4 漫画SpringBoot实战】
  • CMake之CMakeLists.txt语法规则
  • 网安系列【1】:黑客思维、技术与案例解析
  • DDD实战:CQRS模式在电商报表系统中的高性能实践
  • RNN案例人名分类器(完整步骤)
  • MySQL 8.0 OCP 1Z0-908 题目解析(17)
  • POST请求url放参数场景-笔记
  • Spring SseEmitter 系统详细讲解
  • WPF学习笔记(16)树控件TreeView与数据模板
  • WPF学习笔记(22)项面板模板ltemsPanelTemplate与三种模板总结
  • spring-ai-alibaba 1.0.0.2 学习(八)——接入阿里云信息查询服务
  • 深度学习-逻辑回归
  • RJ45 连接器(水晶头)的引脚定义
  • 从0到1解锁Element-Plus组件二次封装El-Dialog动态调用
  • Gemini CLI初体验
  • 二叉树题解——二叉树的层序遍历【LeetCode】队列实现
  • Java中Stream流的使用
  • Web攻防-文件上传黑白名单MIMEJS前端执行权限编码解析OSS存储分域名应用场景
  • 设计模式(九)