文章目录
-
-
- 像素数据与编码图像的区别详解
-
- [1. **像素数据 (Pixel Data)**](#1. 像素数据 (Pixel Data))
- [2. **编码图像 (Encoded Image)**](#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 LR
A[原始编码图像] -->|解码| B[像素数据]
B -->|插值缩放| C[新像素数据]
C -->|编码| D[新编码图像]
在代码中的具体体现
-
解码过程(获取像素数据):
// 原始PNG文件 → 像素数据 PngManager::ImageData sourceImage; pngManager.ReadFromMemory(png_data.data(), png_data.size(), sourceImage); // sourceImage.pixels 现在是像素数据
-
像素处理阶段:
// 像素数据上执行插值 ImageInterpolator::resize(input, width, height, method); // 直接操作像素数组
-
编码过程(生成新图像):
// 处理后的像素数据 → 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");
性能考量
-
解码/编码开销:
- PNG解码:100×100图像约0.5ms
- PNG编码:100×100图像约1.2ms
- 如果处理流程涉及多次缩放操作,应保持在像素数据状态
-
内存占用:
1024×1024图像: - 像素数据(RGBA):4MB - 编码图像(PNG):约0.5-1.5MB
理解这两种数据类型的区别对于优化图像处理流程至关重要。在需要多次操作的场景(如缩放到多种尺寸),应在像素数据状态完成所有操作后统一编码,避免重复解码/编码的开销。
实现文件
cpp
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 0
for (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++;
}
}
#endif
return 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 HasDebugImage
std::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]; // R
rgbData[rgbOffset + 1] = bitmapData[srcOffset + 1]; // G
rgbData[rgbOffset + 2] = bitmapData[srcOffset]; // B
if (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]; // R
rgbData[rgbOffset + 1] = bitmapData[srcOffset + 1]; // G
rgbData[rgbOffset + 2] = bitmapData[srcOffset]; // B
if (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 HasDebugImage
std::cerr << "Unsupported bitmap format" << std::endl;
#endif
//throw std::runtime_error("Unsupported bitmap format");
return false;
}
}
#else
static 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]; // R
rgbPtr[1] = srcPtr[1]; // G
rgbPtr[2] = srcPtr[0]; // B
if (hasAlpha) {
rgbPtr[3] = 0xFF; // 完全不透明
}
*smaskPtr = 0xFF;
break;
}
case FXDIB_Rgba:
case FXDIB_Rgb32:
case FXDIB_Argb: {
// 32位带Alpha处理
rgbPtr[0] = srcPtr[2]; // R
rgbPtr[1] = srcPtr[1]; // G
rgbPtr[2] = srcPtr[0]; // B
if (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]; // B
bitmapData[dstOffset + 1] = rgbData[rgbOffset + 1]; // G
bitmapData[dstOffset + 2] = rgbData[rgbOffset]; // R
break;
}
case FXDIB_Rgba:
case FXDIB_Rgb32:
case FXDIB_Argb: {
// 32位带Alpha处理
bitmapData[dstOffset] = rgbData[rgbOffset + 2]; // B
bitmapData[dstOffset + 1] = rgbData[rgbOffset + 1]; // G
bitmapData[dstOffset + 2] = rgbData[rgbOffset]; // R
if (hasAlpha && rgbData.size() > rgbOffset + 3) {
bitmapData[dstOffset + 3] = smaskData[smaskOffset]; // A
}
else {
bitmapData[dstOffset + 3] = 255; // 不透明
}
break;
}
default:
#if HasDebugImage
std::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;
// 从内存读取PNG
ErrorCode 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+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) {
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) {
// 灰度转RGB
outChannels.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]; // R
outImage.pixels[i * 4 + 1] = channels.rgbData[i * 3 + 1]; // G
outImage.pixels[i * 4 + 2] = channels.rgbData[i * 3 + 2]; // B
outImage.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.114B
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 * 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通道导出为PNG
ErrorCode 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)导出为PNG
ErrorCode 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数据时才导出smask
if (!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]; // R
rgbaData[dstOffset + 1] = dibData.rgbData[srcOffset + 1]; // G
rgbaData[dstOffset + 2] = dibData.rgbData[srcOffset + 2]; // B
// 使用rgbData中的Alpha或smaskData中的Alpha
if (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]; // R
rgbaData[dstOffset + 1] = dibData.rgbData[srcOffset + 1]; // G
rgbaData[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;
}
// 初始化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 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数据中提取RGB
contiguous_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]; // R
contiguous_rgb_data[i * 3 + 1] = dibData.rgbData[i * 4 + 1]; // G
contiguous_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;
}
// 初始化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 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) {
// 导出RGB
auto err = ExportRgbDataToPng(dibData, outRgbPng, compressionLevel);
if (err != ErrorCode::Success) return err;
// 仅当存在Alpha时导出smask
if (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]; // R
imageData.pixels[rgbaOffset + 1] = convertedData.rgbData[rgbOffset + 1]; // G
imageData.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; // 不透明
}
}
}
#endif
private:
// 禁用拷贝和赋值
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 {};
}
// 将缩放后的图像像素数据编码为PNG
std::vector<uint8_t> outputPng;
PngManager pngManager;
if (pngManager.WriteToMemory(targetImage, outputPng) != PngManager::ErrorCode::Success) {
return {};
}
return outputPng;
}
头文件
cpp
/**
* @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