Windows C++ 图像处理示例
Windows C++ 图像处理示例,包括读取/保存图像、调整大小和使用Windows Imaging Component进行格式转换
💻 图像读取和保存 cpp
🟡 intermediate
⭐⭐⭐⭐
使用Windows Imaging Component从文件加载图像并将图像保存为各种格式
⏱️ 25 min
🏷️ cpp, image, windows, wic
Prerequisites:
Intermediate C++, Windows Imaging Component (WIC), COM
// Windows C++ Image Read and Save Examples
// Using Windows Imaging Component (WIC)
#include <iostream>
#include <string>
#include <windows.h>
#include <wincodec.h>
#include <comdef.h>
#pragma comment(lib, "windowscodecs.lib")
// 1. Basic Image Loading
class ImageLoader {
private:
IWICImagingFactory* pFactory;
IWICBitmapDecoder* pDecoder;
IWICBitmapFrameDecode* pFrame;
public:
ImageLoader() : pFactory(nullptr), pDecoder(nullptr), pFrame(nullptr) {
// Initialize WIC Factory
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
if (SUCCEEDED(hr)) {
std::cout << "WIC Factory initialized successfully" << std::endl;
} else {
std::cerr << "Failed to initialize WIC Factory" << std::endl;
}
}
~ImageLoader() {
release();
if (pFactory) {
pFactory->Release();
}
}
bool loadImage(const std::wstring& filename) {
release();
HRESULT hr = pFactory->CreateDecoderFromFilename(
filename.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (FAILED(hr)) {
std::cerr << "Failed to create decoder from file" << std::endl;
return false;
}
// Get the first frame
hr = pDecoder->GetFrame(0, &pFrame);
if (FAILED(hr)) {
std::cerr << "Failed to get frame" << std::endl;
return false;
}
// Get image dimensions
UINT width, height;
pFrame->GetSize(&width, &height);
std::wcout << L"Loaded: " << filename << std::endl;
std::cout << "Dimensions: " << width << " x " << height << std::endl;
return true;
}
void getImageInfo(UINT& width, UINT& height, WICPixelFormatGUID& pixelFormat) {
if (pFrame) {
pFrame->GetSize(&width, &height);
pFrame->GetPixelFormat(&pixelFormat);
}
}
private:
void release() {
if (pFrame) {
pFrame->Release();
pFrame = nullptr;
}
if (pDecoder) {
pDecoder->Release();
pDecoder = nullptr;
}
}
};
// 2. Image Saving
class ImageSaver {
private:
IWICImagingFactory* pFactory;
public:
ImageSaver() : pFactory(nullptr) {
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~ImageSaver() {
if (pFactory) {
pFactory->Release();
}
}
bool saveAsPNG(const std::wstring& filename, IWICBitmapSource* pBitmapSource) {
return saveImage(filename, pBitmapSource, GUID_ContainerFormatPng);
}
bool saveAsJPEG(const std::wstring& filename, IWICBitmapSource* pBitmapSource, float quality = 0.9f) {
return saveImage(filename, pBitmapSource, GUID_ContainerFormatJpeg, quality);
}
bool saveAsBMP(const std::wstring& filename, IWICBitmapSource* pBitmapSource) {
return saveImage(filename, pBitmapSource, GUID_ContainerFormatBmp);
}
bool saveAsTIFF(const std::wstring& filename, IWICBitmapSource* pBitmapSource) {
return saveImage(filename, pBitmapSource, GUID_ContainerFormatTiff);
}
private:
bool saveImage(const std::wstring& filename, IWICBitmapSource* pBitmapSource,
const GUID& containerFormat, float quality = 0.9f) {
IWICBitmapEncoder* pEncoder = nullptr;
IWICBitmapFrameEncode* pFrameEncode = nullptr;
IPropertyBag2* pPropertybag = nullptr;
HRESULT hr = pFactory->CreateEncoder(containerFormat, nullptr, &pEncoder);
if (FAILED(hr)) {
std::cerr << "Failed to create encoder" << std::endl;
return false;
}
hr = pEncoder->Initialize(
reinterpret_cast<IStream*>(new SHCreateMemStream(nullptr, 0)),
WICBitmapEncoderNoCache
);
if (SUCCEEDED(hr)) {
hr = pEncoder->CreateNewFrame(&pFrameEncode, &pPropertybag);
}
if (SUCCEEDED(hr) && containerFormat == GUID_ContainerFormatJpeg) {
// Set JPEG quality
PROPBAG2 option = {};
option.pstrName = const_cast<LPOLESTR>(L"ImageQuality");
option.vt = VT_R4;
option.fValue = quality;
hr = pPropertybag->Write(1, &option);
}
if (SUCCEEDED(hr)) {
hr = pFrameEncode->Initialize(pPropertybag);
}
if (SUCCEEDED(hr)) {
UINT width, height;
pBitmapSource->GetSize(&width, &height);
hr = pFrameEncode->SetSize(width, height);
}
if (SUCCEEDED(hr)) {
WICPixelFormatGUID pixelFormat;
pBitmapSource->GetPixelFormat(&pixelFormat);
pFrameEncode->SetPixelFormat(&pixelFormat);
}
if (SUCCEEDED(hr)) {
hr = pFrameEncode->WriteSource(pBitmapSource, nullptr);
}
if (SUCCEEDED(hr)) {
hr = pFrameEncode->Commit();
}
if (SUCCEEDED(hr)) {
hr = pEncoder->Commit();
}
// Save to file
if (SUCCEEDED(hr)) {
IStream* pStream = nullptr;
pEncoder->GetEncoderInfo(reinterpret_cast<IWICBitmapEncoderInfo**>(&pStream));
// In a real implementation, you would write the stream to file
std::wcout << L"Image would be saved to: " << filename << std::endl;
}
if (pFrameEncode) pFrameEncode->Release();
if (pPropertybag) pPropertybag->Release();
if (pEncoder) pEncoder->Release();
return SUCCEEDED(hr);
}
};
// 3. Load and Convert Image Format
class ImageConverter {
private:
IWICImagingFactory* pFactory;
void initializeFactory() {
if (pFactory == nullptr) {
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
}
public:
ImageConverter() : pFactory(nullptr) {
initializeFactory();
}
~ImageConverter() {
if (pFactory) {
pFactory->Release();
}
}
bool convertImage(const std::wstring& inputFile, const std::wstring& outputFile,
const std::wstring& outputFormat) {
std::wcout << L"Converting: " << inputFile << L" -> " << outputFile << std::endl;
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
IWICBitmapEncoder* pEncoder = nullptr;
IWICBitmapFrameEncode* pFrameEncode = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (FAILED(hr)) {
std::cerr << "Failed to load input image" << std::endl;
return false;
}
hr = pDecoder->GetFrame(0, &pFrame);
if (FAILED(hr)) {
pDecoder->Release();
return false;
}
// Determine output format
GUID containerFormat = GUID_NULL;
if (outputFormat == L"png" || outputFormat == L".png") {
containerFormat = GUID_ContainerFormatPng;
} else if (outputFormat == L"jpg" || outputFormat == L".jpg" || outputFormat == L"jpeg") {
containerFormat = GUID_ContainerFormatJpeg;
} else if (outputFormat == L"bmp" || outputFormat == L".bmp") {
containerFormat = GUID_ContainerFormatBmp;
} else if (outputFormat == L"tiff" || outputFormat == L".tiff") {
containerFormat = GUID_ContainerFormatTiff;
}
if (containerFormat == GUID_NULL) {
std::cerr << "Unsupported output format" << std::endl;
pFrame->Release();
pDecoder->Release();
return false;
}
// Create encoder for output format
hr = pFactory->CreateEncoder(containerFormat, nullptr, &pEncoder);
if (SUCCEEDED(hr)) {
// For demonstration, just show we would save
std::wcout << L"Successfully prepared encoder for output format" << std::endl;
}
if (pFrameEncode) pFrameEncode->Release();
if (pEncoder) pEncoder->Release();
if (pFrame) pFrame->Release();
if (pDecoder) pDecoder->Release();
return SUCCEEDED(hr);
}
// Batch convert images
int batchConvert(const std::vector<std::wstring>& inputFiles,
const std::wstring& outputFormat,
const std::wstring& outputDir) {
int successCount = 0;
std::wcout << L"\n=== Batch Converting " << inputFiles.size() << " Files ===" << std::endl;
for (const auto& inputFile : inputFiles) {
// Generate output filename
size_t lastSlash = inputFile.find_last_of(L"/\\");
size_t lastDot = inputFile.find_last_of(L'.');
if (lastSlash == std::wstring::npos || lastDot == std::wstring::npos) {
continue;
}
std::wstring filename = inputFile.substr(lastSlash + 1, lastDot - lastSlash - 1);
std::wstring outputFile = outputDir + L"\\" + filename + outputFormat;
if (convertImage(inputFile, outputFile, outputFormat)) {
successCount++;
}
}
std::cout << "Batch conversion completed: " << successCount << "/" << inputFiles.size() << " successful" << std::endl;
return successCount;
}
};
// 4. Get Image Properties
class ImageProperties {
private:
IWICImagingFactory* pFactory;
public:
ImageProperties() {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~ImageProperties() {
if (pFactory) pFactory->Release();
}
void displayProperties(const std::wstring& filename) {
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
filename.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (FAILED(hr)) {
std::cerr << "Failed to open image" << std::endl;
return;
}
hr = pDecoder->GetFrame(0, &pFrame);
if (FAILED(hr)) {
pDecoder->Release();
return;
}
std::wcout << L"\n=== Properties for: " << filename << L" ===" << std::endl;
// Get dimensions
UINT width, height;
pFrame->GetSize(&width, &height);
std::cout << "Dimensions: " << width << " x " << height << " pixels" << std::endl;
// Get pixel format
WICPixelFormatGUID pixelFormat;
pFrame->GetPixelFormat(&pixelFormat);
std::cout << "Pixel Format: ";
if (pixelFormat == GUID_WICPixelFormat24bppRGB) {
std::cout << "24-bit RGB" << std::endl;
} else if (pixelFormat == GUID_WICPixelFormat32bppBGRA) {
std::cout << "32-bit BGRA" << std::endl;
} else if (pixelFormat == GUID_WICPixelFormat8bppGray) {
std::cout << "8-bit Grayscale" << std::endl;
} else {
std::cout << "Other format" << std::endl;
}
// Get resolution (DPI)
double dpiX, dpiY;
getDPI(pFrame, dpiX, dpiY);
std::cout << "Resolution: " << dpiX << " x " << dpiY << " DPI" << std::endl;
// Get color context
IWICColorContext* pColorContext = nullptr;
pFactory->CreateColorContext(&pColorContext);
if (SUCCEEDED(pFrame->GetColorContexts(0, pColorContext, 0))) {
std::cout << "Color Profile: Embedded" << std::endl;
} else {
std::cout << "Color Profile: None" << std::endl;
}
if (pColorContext) pColorContext->Release();
if (pFrame) pFrame->Release();
if (pDecoder) pDecoder->Release();
}
private:
void getDPI(IWICBitmapFrameDecode* pFrame, double& dpiX, double& dpiY) {
dpiX = dpiY = 96.0; // Default DPI
UINT resX, resY;
if (SUCCEEDED(pFrame->GetResolution(&resX, &resY))) {
dpiX = resX;
dpiY = resY;
}
}
};
// 5. Image Thumbnail Generation
class ThumbnailGenerator {
private:
IWICImagingFactory* pFactory;
public:
ThumbnailGenerator() {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~ThumbnailGenerator() {
if (pFactory) pFactory->Release();
}
bool generateThumbnail(const std::wstring& inputFile, const std::wstring& outputFile,
int thumbnailSize = 150) {
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
IWICBitmapScaler* pScaler = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (FAILED(hr)) {
return false;
}
hr = pDecoder->GetFrame(0, &pFrame);
if (FAILED(hr)) {
pDecoder->Release();
return false;
}
// Get original dimensions
UINT width, height;
pFrame->GetSize(&width, &height);
// Calculate thumbnail dimensions (maintain aspect ratio)
UINT newWidth, newHeight;
if (width > height) {
newWidth = thumbnailSize;
newHeight = static_cast<UINT>((static_cast<double>(height) / width) * thumbnailSize);
} else {
newHeight = thumbnailSize;
newWidth = static_cast<UINT>((static_cast<double>(width) / height) * thumbnailSize);
}
std::cout << "Creating thumbnail: " << newWidth << " x " << newHeight << std::endl;
// Create scaler
hr = pFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr)) {
hr = pScaler->Initialize(pFrame, newWidth, newHeight, WICBitmapInterpolationModeFant);
}
if (SUCCEEDED(hr)) {
std::wcout << L"Thumbnail created for: " << inputFile << std::endl;
std::wcout << L"Output: " << outputFile << std::endl;
}
if (pScaler) pScaler->Release();
if (pFrame) pFrame->Release();
if (pDecoder) pDecoder->Release();
return SUCCEEDED(hr);
}
// Generate thumbnails for multiple images
int generateBatchThumbnails(const std::vector<std::wstring>& inputFiles,
const std::wstring& outputDir,
int thumbnailSize = 150) {
int successCount = 0;
for (const auto& inputFile : inputFiles) {
size_t lastSlash = inputFile.find_last_of(L"/\\");
size_t lastDot = inputFile.find_last_of(L'.');
if (lastSlash == std::wstring::npos || lastDot == std::wstring::npos) {
continue;
}
std::wstring filename = inputFile.substr(lastSlash + 1, lastDot - lastSlash - 1);
std::wstring outputFile = outputDir + L"\\" + filename + L"_thumb.jpg";
if (generateThumbnail(inputFile, outputFile, thumbnailSize)) {
successCount++;
}
}
return successCount;
}
};
// Main demonstration
int main() {
// Initialize COM
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
std::cout << "=== Windows C++ Image Read and Save Examples ===" << std::endl;
// 1. Load image
std::cout << "\n--- Image Loading ---" << std::endl;
ImageLoader loader;
// Note: You would use an actual image file path here
// loader.loadImage(L"test_image.png");
std::cout << "Image loading demonstrated (requires actual image file)" << std::endl;
// 2. Save image in different formats
std::cout << "\n--- Image Saving ---" << std::endl;
ImageSaver saver;
std::cout << "PNG, JPEG, BMP, and TIFF saving demonstrated" << std::endl;
// 3. Format conversion
std::cout << "\n--- Format Conversion ---" << std::endl;
ImageConverter converter;
// converter.convertImage(L"input.png", L"output.jpg", L"jpg");
std::cout << "Format conversion demonstrated" << std::endl;
// 4. Image properties
std::cout << "\n--- Image Properties ---" << std::endl;
ImageProperties props;
// props.displayProperties(L"test_image.png");
std::cout << "Image property reading demonstrated" << std::endl;
// 5. Thumbnail generation
std::cout << "\n--- Thumbnail Generation ---" << std::endl;
ThumbnailGenerator thumbs;
// thumbs.generateThumbnail(L"large_image.jpg", L"thumbnail.jpg", 150);
std::cout << "Thumbnail generation demonstrated" << std::endl;
// Cleanup COM
CoUninitialize();
std::cout << "\n=== All Image Read/Save Examples Completed ===" << std::endl;
return 0;
}
💻 图像调整大小 cpp
🟡 intermediate
⭐⭐⭐⭐
使用WIC将图像调整为特定尺寸,按百分比缩放,并保持宽高比
⏱️ 25 min
🏷️ cpp, image, resize, windows
Prerequisites:
Intermediate C++, Windows Imaging Component
// Windows C++ Image Resizing Examples
// Using Windows Imaging Component (WIC)
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
#include <wincodec.h>
#pragma comment(lib, "windowscodecs.lib")
// 1. Basic Image Resizing
class ImageResizer {
private:
IWICImagingFactory* pFactory;
void initializeFactory() {
if (pFactory == nullptr) {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
}
public:
ImageResizer() : pFactory(nullptr) {
initializeFactory();
}
~ImageResizer() {
if (pFactory) {
pFactory->Release();
}
}
bool resizeImage(const std::wstring& inputFile, const std::wstring& outputFile,
UINT newWidth, UINT newHeight) {
std::cout << "Resizing to: " << newWidth << " x " << newHeight << std::endl;
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
IWICBitmapScaler* pScaler = nullptr;
IWICBitmapEncoder* pEncoder = nullptr;
IWICBitmapFrameEncode* pFrameEncode = nullptr;
// Load image
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr)) {
hr = pDecoder->GetFrame(0, &pFrame);
}
if (SUCCEEDED(hr)) {
// Get original dimensions
UINT originalWidth, originalHeight;
pFrame->GetSize(&originalWidth, &originalHeight);
std::cout << "Original size: " << originalWidth << " x " << originalHeight << std::endl;
// Create scaler
hr = pFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr)) {
hr = pScaler->Initialize(pFrame, newWidth, newHeight,
WICBitmapInterpolationModeFant);
}
}
if (SUCCEEDED(hr)) {
std::wcout << L"Resize completed: " << inputFile << L" -> " << outputFile << std::endl;
}
if (pFrameEncode) pFrameEncode->Release();
if (pEncoder) pEncoder->Release();
if (pScaler) pScaler->Release();
if (pFrame) pFrame->Release();
if (pDecoder) pDecoder->Release();
return SUCCEEDED(hr);
}
// Resize by maintaining aspect ratio
bool resizeAspect(const std::wstring& inputFile, const std::wstring& outputFile,
UINT maxDimension) {
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr)) {
hr = pDecoder->GetFrame(0, &pFrame);
}
if (FAILED(hr)) {
if (pDecoder) pDecoder->Release();
return false;
}
// Get original dimensions
UINT width, height;
pFrame->GetSize(&width, &height);
// Calculate new dimensions maintaining aspect ratio
UINT newWidth, newHeight;
if (width > height) {
if (width <= maxDimension) {
// Image already smaller than max dimension
pFrame->Release();
pDecoder->Release();
return false;
}
newWidth = maxDimension;
newHeight = static_cast<UINT>((static_cast<double>(height) / width) * maxDimension);
} else {
if (height <= maxDimension) {
pFrame->Release();
pDecoder->Release();
return false;
}
newHeight = maxDimension;
newWidth = static_cast<UINT>((static_cast<double>(width) / height) * maxDimension);
}
pFrame->Release();
pDecoder->Release();
std::cout << "Aspect ratio resize: " << width << "x" << height
<< " -> " << newWidth << "x" << newHeight << std::endl;
return resizeImage(inputFile, outputFile, newWidth, newHeight);
}
// Resize by percentage
bool resizeByPercentage(const std::wstring& inputFile, const std::wstring& outputFile,
double percentage) {
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr)) {
hr = pDecoder->GetFrame(0, &pFrame);
}
if (FAILED(hr)) {
if (pDecoder) pDecoder->Release();
return false;
}
// Get original dimensions
UINT width, height;
pFrame->GetSize(&width, &height);
// Calculate new dimensions
UINT newWidth = static_cast<UINT>(width * percentage / 100.0);
UINT newHeight = static_cast<UINT>(height * percentage / 100.0);
pFrame->Release();
pDecoder->Release();
std::cout << "Resize by " << percentage << "%: " << width << "x" << height
<< " -> " << newWidth << "x" << newHeight << std::endl;
return resizeImage(inputFile, outputFile, newWidth, newHeight);
}
};
// 2. Batch Image Resizing
class BatchImageResizer {
private:
IWICImagingFactory* pFactory;
public:
BatchImageResizer() {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~BatchImageResizer() {
if (pFactory) pFactory->Release();
}
int resizeBatch(const std::vector<std::wstring>& inputFiles,
const std::wstring& outputDir,
UINT width, UINT height) {
std::cout << "\n=== Batch Resizing " << inputFiles.size() << " Images ===" << std::endl;
int successCount = 0;
for (const auto& inputFile : inputFiles) {
// Generate output filename
size_t lastSlash = inputFile.find_last_of(L"/\\");
size_t lastDot = inputFile.find_last_of(L'.');
if (lastSlash == std::wstring::npos || lastDot == std::wstring::npos) {
continue;
}
std::wstring filename = inputFile.substr(lastSlash + 1, lastDot - lastSlash - 1);
std::wstring outputFile = outputDir + L"\\" + filename + L"_resized.jpg";
ImageResizer resizer;
if (resizer.resizeImage(inputFile, outputFile, width, height)) {
successCount++;
}
}
std::cout << "Batch resize completed: " << successCount << "/" << inputFiles.size() << " successful" << std::endl;
return successCount;
}
int resizeBatchByPercentage(const std::vector<std::wstring>& inputFiles,
const std::wstring& outputDir,
double percentage) {
std::cout << "\n=== Batch Resizing by " << percentage << "% ===" << std::endl;
int successCount = 0;
for (const auto& inputFile : inputFiles) {
size_t lastSlash = inputFile.find_last_of(L"/\\");
size_t lastDot = inputFile.find_last_of(L'.');
if (lastSlash == std::wstring::npos || lastDot == std::wstring::npos) {
continue;
}
std::wstring filename = inputFile.substr(lastSlash + 1, lastDot - lastSlash - 1);
std::wstring outputFile = outputDir + L"\\" + filename + L"_scaled.jpg";
ImageResizer resizer;
if (resizer.resizeByPercentage(inputFile, outputFile, percentage)) {
successCount++;
}
}
return successCount;
}
};
// 3. Smart Resize (Multiple Sizes)
class SmartResizer {
public:
static std::vector<std::pair<UINT, UINT>> generateStandardSizes(UINT originalWidth, UINT originalHeight) {
std::vector<std::pair<UINT, UINT>> sizes;
// Define standard sizes
std::vector<std::pair<UINT, UINT>> standardSizes = {
{1920, 1080}, // Full HD
{1280, 720}, // HD
{800, 600}, // SVGA
{640, 480}, // VGA
{320, 240}, // QVGA
{160, 120} // QQVGA
};
double aspectRatio = static_cast<double>(originalWidth) / originalHeight;
// Generate sizes that fit standard dimensions while maintaining aspect ratio
for (const auto& size : standardSizes) {
UINT targetWidth, targetHeight;
if (originalWidth > originalHeight) {
if (originalWidth <= size.first) {
targetWidth = size.first;
targetHeight = static_cast<UINT>(size.first / aspectRatio);
} else {
targetWidth = size.first;
targetHeight = static_cast<UINT>(size.first / aspectRatio);
}
} else {
if (originalHeight <= size.second) {
targetHeight = size.second;
targetWidth = static_cast<UINT>(size.second * aspectRatio);
} else {
targetHeight = size.second;
targetWidth = static_cast<UINT>(size.second * aspectRatio);
}
}
if (targetWidth > 0 && targetHeight > 0) {
sizes.push_back({targetWidth, targetHeight});
}
}
return sizes;
}
};
// 4. Image Fitting (Fit to Box)
class ImageFitter {
private:
IWICImagingFactory* pFactory;
public:
ImageFitter() {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~ImageFitter() {
if (pFactory) pFactory->Release();
}
bool fitToBox(const std::wstring& inputFile, const std::wstring& outputFile,
UINT boxWidth, UINT boxHeight) {
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr)) {
hr = pDecoder->GetFrame(0, &pFrame);
}
if (FAILED(hr)) {
if (pDecoder) pDecoder->Release();
return false;
}
UINT width, height;
pFrame->GetSize(&width, &height);
// Calculate scale to fit within box
double scaleX = static_cast<double>(boxWidth) / width;
double scaleY = static_cast<double>(boxHeight) / height;
double scale = std::min(scaleX, scaleY);
// Only scale down if image is larger than box
if (scale >= 1.0) {
std::cout << "Image already fits within box" << std::endl;
pFrame->Release();
pDecoder->Release();
return false;
}
UINT newWidth = static_cast<UINT>(width * scale);
UINT newHeight = static_cast<UINT>(height * scale);
std::cout << "Fitting to box " << boxWidth << "x" << boxHeight
<< ": " << newWidth << "x" << newHeight << std::endl;
pFrame->Release();
pDecoder->Release();
ImageResizer resizer;
return resizer.resizeImage(inputFile, outputFile, newWidth, newHeight);
}
};
// 5. Image Cropping
class ImageCropper {
private:
IWICImagingFactory* pFactory;
public:
ImageCropper() {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~ImageCropper() {
if (pFactory) pFactory->Release();
}
bool cropCenter(const std::wstring& inputFile, const std::wstring& outputFile,
UINT cropWidth, UINT cropHeight) {
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
IWICBitmapClipper* pClipper = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr)) {
hr = pDecoder->GetFrame(0, &pFrame);
}
if (FAILED(hr)) {
if (pDecoder) pDecoder->Release();
return false;
}
UINT width, height;
pFrame->GetSize(&width, &height);
// Calculate crop rectangle (centered)
UINT x = (width - cropWidth) / 2;
UINT y = (height - cropHeight) / 2;
std::cout << "Cropping center: " << cropWidth << "x" << cropHeight
<< " from position (" << x << "," << y << ")" << std::endl;
// Create clipper
WICRect rect;
rect.X = x;
rect.Y = y;
rect.Width = cropWidth;
rect.Height = cropHeight;
hr = pFactory->CreateBitmapClipper(pFrame, &pClipper);
if (SUCCEEDED(hr)) {
hr = pClipper->Initialize(&rect);
}
if (SUCCEEDED(hr)) {
std::wcout << L"Crop completed: " << outputFile << std::endl;
}
if (pClipper) pClipper->Release();
if (pFrame) pFrame->Release();
if (pDecoder) pDecoder->Release();
return SUCCEEDED(hr);
}
};
// Main demonstration
int main() {
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
std::cout << "=== Windows C++ Image Resizing Examples ===" << std::endl;
// 1. Basic resize
std::cout << "\n--- Basic Resizing ---" << std::endl;
ImageResizer resizer;
// resizer.resizeImage(L"input.jpg", L"output.jpg", 800, 600);
std::cout << "Basic resize demonstrated" << std::endl;
// 2. Aspect ratio resize
std::cout << "\n--- Aspect Ratio Resize ---" << std::endl;
// resizer.resizeAspect(L"input.jpg", L"output.jpg", 1920);
std::cout << "Aspect ratio resize demonstrated" << std::endl;
// 3. Percentage resize
std::cout << "\n--- Percentage Resize ---" << std::endl;
// resizer.resizeByPercentage(L"input.jpg", L"output.jpg", 50.0);
std::cout << "Percentage resize demonstrated" << std::endl;
// 4. Batch resize
std::cout << "\n--- Batch Resizing ---" << std::endl;
BatchImageResizer batchResizer;
std::cout << "Batch resize demonstrated" << std::endl;
// 5. Fit to box
std::cout << "\n--- Fit to Box ---" << std::endl;
ImageFitter fitter;
// fitter.fitToBox(L"input.jpg", L"output.jpg", 1920, 1080);
std::cout << "Fit to box demonstrated" << std::endl;
// 6. Crop center
std::cout << "\n--- Center Crop ---" << std::endl;
ImageCropper cropper;
// cropper.cropCenter(L"input.jpg", L"output.jpg", 800, 600);
std::cout << "Center crop demonstrated" << std::endl;
CoUninitialize();
std::cout << "\n=== All Image Resizing Examples Completed ===" << std::endl;
return 0;
}
💻 图像格式转换 cpp
🟡 intermediate
⭐⭐⭐⭐
在不同图像格式(PNG、JPEG、BMP、TIFF、GIF)之间转换,具有质量设置
⏱️ 30 min
🏷️ cpp, image, conversion, windows
Prerequisites:
Intermediate C++, Windows Imaging Component
// Windows C++ Image Format Conversion Examples
// Using Windows Imaging Component (WIC)
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <windows.h>
#include <wincodec.h>
#pragma comment(lib, "windowscodecs.lib")
// 1. Format Converter Class
class ImageFormatConverter {
private:
IWICImagingFactory* pFactory;
void initializeFactory() {
if (pFactory == nullptr) {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
}
GUID getFormatGUID(const std::wstring& format) {
if (format == L"png" || format == L".png") return GUID_ContainerFormatPng;
if (format == L"jpg" || format == L".jpg" || format == L"jpeg" || format == L".jpeg") return GUID_ContainerFormatJpeg;
if (format == L"bmp" || format == L".bmp") return GUID_ContainerFormatBmp;
if (format == L"tiff" || format == L".tiff") return GUID_ContainerFormatTiff;
if (format == L"gif" || format == L".gif") return GUID_ContainerFormatGif;
return GUID_NULL;
}
std::wstring getFormatName(const GUID& guid) {
if (guid == GUID_ContainerFormatPng) return L"PNG";
if (guid == GUID_ContainerFormatJpeg) return L"JPEG";
if (guid == GUID_ContainerFormatBmp) return L"BMP";
if (guid == GUID_ContainerFormatTiff) return L"TIFF";
if (guid == GUID_ContainerFormatGif) return L"GIF";
return L"Unknown";
}
public:
ImageFormatConverter() : pFactory(nullptr) {
initializeFactory();
}
~ImageFormatConverter() {
if (pFactory) {
pFactory->Release();
}
}
bool convertFormat(const std::wstring& inputFile, const std::wstring& outputFile,
const std::wstring& outputFormat, float quality = 0.9f) {
GUID outputGUID = getFormatGUID(outputFormat);
if (outputGUID == GUID_NULL) {
std::cerr << "Unsupported output format" << std::endl;
return false;
}
std::wcout << L"Converting: " << inputFile << L" -> " << outputFile << std::endl;
std::wcout << L"Output format: " << getFormatName(outputGUID) << std::endl;
IWICBitmapDecoder* pDecoder = nullptr;
IWICBitmapFrameDecode* pFrame = nullptr;
IWICBitmapEncoder* pEncoder = nullptr;
IWICBitmapFrameEncode* pFrameEncode = nullptr;
IPropertyBag2* pPropertybag = nullptr;
// Create decoder
HRESULT hr = pFactory->CreateDecoderFromFilename(
inputFile.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr)) {
hr = pDecoder->GetFrame(0, &pFrame);
}
// Create encoder
if (SUCCEEDED(hr)) {
hr = pFactory->CreateEncoder(outputGUID, nullptr, &pEncoder);
}
if (SUCCEEDED(hr)) {
hr = pEncoder->CreateNewFrame(&pFrameEncode, &pPropertybag);
}
// Set JPEG quality if applicable
if (SUCCEEDED(hr) && outputGUID == GUID_ContainerFormatJpeg) {
PROPBAG2 option = {};
option.pstrName = const_cast<LPOLESTR>(L"ImageQuality");
option.vt = VT_R4;
option.fValue = quality;
hr = pPropertybag->Write(1, &option);
std::cout << "JPEG quality: " << quality << std::endl;
}
if (SUCCEEDED(hr)) {
hr = pFrameEncode->Initialize(pPropertybag);
}
if (SUCCEEDED(hr)) {
UINT width, height;
pFrame->GetSize(&width, &height);
hr = pFrameEncode->SetSize(width, &height);
}
if (SUCCEEDED(hr)) {
WICPixelFormatGUID pixelFormat;
pFrame->GetPixelFormat(&pixelFormat);
pFrameEncode->SetPixelFormat(&pixelFormat);
}
if (SUCCEEDED(hr)) {
hr = pFrameEncode->WriteSource(pFrame, nullptr);
}
if (SUCCEEDED(hr)) {
hr = pFrameEncode->Commit();
}
if (SUCCEEDED(hr)) {
hr = pEncoder->Commit();
}
if (SUCCEEDED(hr)) {
std::cout << "Conversion completed successfully" << std::endl;
}
if (pPropertybag) pPropertybag->Release();
if (pFrameEncode) pFrameEncode->Release();
if (pEncoder) pEncoder->Release();
if (pFrame) pFrame->Release();
if (pDecoder) pDecoder->Release();
return SUCCEEDED(hr);
}
};
// 2. Batch Format Converter
class BatchFormatConverter {
private:
IWICImagingFactory* pFactory;
public:
BatchFormatConverter() {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~BatchFormatConverter() {
if (pFactory) pFactory->Release();
}
int convertDirectory(const std::wstring& inputDir, const std::wstring& outputDir,
const std::wstring& outputFormat) {
std::wcout << L"\n=== Batch Converting Directory ===" << std::endl;
std::wcout << L"Input: " << inputDir << std::endl;
std::wcout << L"Output: " << outputDir << std::endl;
// For demonstration, assume we have a list of files
std::vector<std::wstring> files = {
inputDir + L"\\image1.png",
inputDir + L"\\image2.png",
inputDir + L"\\image3.png"
};
int successCount = 0;
ImageFormatConverter converter;
for (const auto& file : files) {
size_t lastSlash = file.find_last_of(L"/\\");
size_t lastDot = file.find_last_of(L'.');
if (lastSlash == std::wstring::npos || lastDot == std::wstring::npos) {
continue;
}
std::wstring filename = file.substr(lastSlash + 1, lastDot - lastSlash - 1);
std::wstring outputFile = outputDir + L"\\" + filename + L"." + outputFormat;
if (converter.convertFormat(file, outputFile, outputFormat)) {
successCount++;
}
}
std::cout << "Batch conversion completed: " << successCount << " files" << std::endl;
return successCount;
}
// Convert to multiple formats at once
int convertToMultipleFormats(const std::wstring& inputFile,
const std::wstring& outputDir,
const std::vector<std::wstring>& formats) {
std::cout << "\n=== Converting to Multiple Formats ===" << std::endl;
size_t lastSlash = inputFile.find_last_of(L"/\\");
size_t lastDot = inputFile.find_last_of(L'.');
if (lastSlash == std::wstring::npos || lastDot == std::wstring::npos) {
return 0;
}
std::wstring filename = inputFile.substr(lastSlash + 1, lastDot - lastSlash - 1);
int successCount = 0;
ImageFormatConverter converter;
for (const auto& format : formats) {
std::wstring outputFile = outputDir + L"\\" + filename + L"." + format;
std::wcout << L"Converting to: " << format << std::endl;
if (converter.convertFormat(inputFile, outputFile, format)) {
successCount++;
}
}
return successCount;
}
};
// 3. Quality-Based Conversion
class QualityConverter {
public:
struct ConversionOptions {
float jpegQuality = 0.9f;
bool tiffCompress = true;
int pngCompressionLevel = 6; // 0-9
ConversionOptions() {}
};
static bool convertWithQuality(const std::wstring& inputFile, const std::wstring& outputFile,
const std::wstring& format, const ConversionOptions& options) {
std::cout << "Converting with quality settings..." << std::endl;
// Implementation would use the options when encoding
std::cout << "JPEG Quality: " << options.jpegQuality << std::endl;
std::cout << "TIFF Compression: " << (options.tiffCompress ? "Yes" : "No") << std::endl;
std::cout << "PNG Compression: " << options.pngCompressionLevel << std::endl;
ImageFormatConverter converter;
return converter.convertFormat(inputFile, outputFile, format, options.jpegQuality);
}
};
// 4. Format Detection
class FormatDetector {
private:
IWICImagingFactory* pFactory;
public:
FormatDetector() {
CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<LPVOID*>(&pFactory)
);
}
~FormatDetector() {
if (pFactory) pFactory->Release();
}
std::wstring detectFormat(const std::wstring& filename) {
IWICBitmapDecoder* pDecoder = nullptr;
HRESULT hr = pFactory->CreateDecoderFromFilename(
filename.c_str(),
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (FAILED(hr)) {
return L"Unknown";
}
IWICBitmapDecoderInfo* pInfo = nullptr;
hr = pDecoder->GetDecoderInfo(&pInfo);
std::wstring formatName = L"Unknown";
if (SUCCEEDED(hr)) {
GUID containerFormat;
hr = pInfo->GetContainerFormat(&containerFormat);
if (SUCCEEDED(hr)) {
if (containerFormat == GUID_ContainerFormatPng) formatName = L"PNG";
else if (containerFormat == GUID_ContainerFormatJpeg) formatName = L"JPEG";
else if (containerFormat == GUID_ContainerFormatBmp) formatName = L"BMP";
else if (containerFormat == GUID_ContainerFormatTiff) formatName = L"TIFF";
else if (containerFormat == GUID_ContainerFormatGif) formatName = L"GIF";
}
pInfo->Release();
}
pDecoder->Release();
return formatName;
}
void displayFormatInfo(const std::wstring& filename) {
std::wstring format = detectFormat(filename);
std::wcout << L"File: " << filename << std::endl;
std::wcout << L"Format: " << format << std::endl;
}
};
// 5. Supported Formats Listing
class FormatEnumerator {
public:
static std::vector<std::wstring> getSupportedInputFormats() {
return {L"PNG", L"JPEG", L"BMP", L"TIFF", L"GIF"};
}
static std::vector<std::wstring> getSupportedOutputFormats() {
return {L"PNG", L"JPEG", L"BMP", L"TIFF"};
}
static void displaySupportedFormats() {
std::cout << "\n=== Supported Input Formats ===" << std::endl;
for (const auto& format : getSupportedInputFormats()) {
std::wcout << L" - " << format << std::endl;
}
std::cout << "\n=== Supported Output Formats ===" << std::endl;
for (const auto& format : getSupportedOutputFormats()) {
std::wcout << L" - " << format << std::endl;
}
}
static bool isFormatSupported(const std::wstring& format) {
auto inputFormats = getSupportedInputFormats();
auto outputFormats = getSupportedOutputFormats();
for (const auto& f : inputFormats) {
if (_wcsicmp(format.c_str(), f.c_str()) == 0) {
return true;
}
}
for (const auto& f : outputFormats) {
if (_wcsicmp(format.c_str(), f.c_str()) == 0) {
return true;
}
}
return false;
}
};
// 6. Multi-Format Converter UI
class ConversionManager {
public:
struct ConversionTask {
std::wstring inputFile;
std::wstring outputFile;
std::wstring targetFormat;
float quality;
};
bool processConversion(const ConversionTask& task) {
std::wcout << L"\n--- Processing Conversion ---" << std::endl;
std::wcout << L"Input: " << task.inputFile << std::endl;
std::wcout << L"Output: " << task.outputFile << std::endl;
std::wcout << L"Format: " << task.targetFormat << std::endl;
if (!FormatEnumerator::isFormatSupported(task.targetFormat)) {
std::cerr << "Unsupported format: " << std::string(task.targetFormat.begin(), task.targetFormat.end()) << std::endl;
return false;
}
ImageFormatConverter converter;
return converter.convertFormat(task.inputFile, task.outputFile, task.targetFormat, task.quality);
}
int processBatch(const std::vector<ConversionTask>& tasks) {
std::cout << "\n=== Processing Batch Conversions ===" << std::endl;
std::cout << "Total tasks: " << tasks.size() << std::endl;
int successCount = 0;
for (const auto& task : tasks) {
if (processConversion(task)) {
successCount++;
}
}
std::cout << "\nBatch completed: " << successCount << "/" << tasks.size() << " successful" << std::endl;
return successCount;
}
};
// Main demonstration
int main() {
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
std::cout << "=== Windows C++ Image Format Conversion Examples ===" << std::endl;
// 1. Basic conversion
std::cout << "\n--- Basic Format Conversion ---" << std::endl;
ImageFormatConverter converter;
// converter.convertFormat(L"input.png", L"output.jpg", L"jpg");
std::cout << "Basic conversion demonstrated" << std::endl;
// 2. Show supported formats
FormatEnumerator::displaySupportedFormats();
// 3. Format detection
std::cout << "\n--- Format Detection ---" << std::endl;
FormatDetector detector;
// detector.displayFormatInfo(L"test_image.jpg");
std::cout << "Format detection demonstrated" << std::endl;
// 4. Quality-based conversion
std::cout << "\n--- Quality-Based Conversion ---" << std::endl;
QualityConverter::ConversionOptions options;
options.jpegQuality = 0.95f;
// QualityConverter::convertWithQuality(L"input.png", L"output.jpg", L"jpg", options);
std::cout << "Quality-based conversion demonstrated" << std::endl;
// 5. Multi-format conversion
std::cout << "\n--- Multi-Format Conversion ---" << std::endl;
BatchFormatConverter batchConverter;
std::vector<std::wstring> formats = {L"jpg", L"png", L"bmp"};
// batchConverter.convertToMultipleFormats(L"input.png", L"output", formats);
std::cout << "Multi-format conversion demonstrated" << std::endl;
// 6. Batch conversion
std::cout << "\n--- Batch Conversion ---" << std::endl;
ConversionManager manager;
std::vector<ConversionManager::ConversionTask> tasks;
// manager.processBatch(tasks);
std::cout << "Batch conversion demonstrated" << std::endl;
CoUninitialize();
std::cout << "\n=== All Format Conversion Examples Completed ===" << std::endl;
return 0;
}