如何使用 Win32 解码 JPEG?
How to Decode JPEG Using Win32?
我有一块内存包含 JPEG 的原始字节,我想将其转换为 24 位 RGB,以便我可以使用 StretchDIBits 渲染它。我环顾了 msdn,但是天哪……我真的不想使用任何第三方库,如果不需要的话,甚至不想使用 C++。有什么建议么?我希望只有一些函数,比如 DecodeJpeg()
之类的...
我想出了一个使用 WIC 的解决方案,它似乎没有使用 C++,但我无法将以下代码编译为 C,所以不确定。花了很多时间将各个部分拼凑在一起,但就是这样!
#include <Wincodec.h>
#include <stdio.h>
#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Windowscodecs.lib")
#define MIN(A, B) (A < B ? A : B)
void
Win32DecodeJpeg(unsigned int ImageDataSize, void *ImageData,
unsigned int DestSize, void *Dest)
{
static IWICImagingFactory *IWICFactory;
if(IWICFactory == NULL)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&IWICFactory));
}
IWICStream *Stream;
IWICFactory->CreateStream(&Stream);
Stream->InitializeFromMemory((unsigned char *)ImageData, ImageDataSize);
IWICBitmapDecoder *BitmapDecoder;
IWICFactory->CreateDecoderFromStream(Stream, NULL, WICDecodeMetadataCacheOnDemand, &BitmapDecoder);
IWICBitmapFrameDecode *FrameDecode;
BitmapDecoder->GetFrame(0, &FrameDecode);
IWICFormatConverter *FormatConverter;
IWICFactory->CreateFormatConverter(&FormatConverter);
FormatConverter->Initialize(FrameDecode,
GUID_WICPixelFormat24bppBGR,
WICBitmapDitherTypeNone,
nullptr,
0.0f,
WICBitmapPaletteTypeCustom);
IWICBitmap *Bitmap;
IWICFactory->CreateBitmapFromSource(FormatConverter, WICBitmapCacheOnDemand, &Bitmap);
unsigned int Width, Height;
Bitmap->GetSize(&Width, &Height);
WICRect Rect = {0, 0, (int)Width, (int)Height};
IWICBitmapLock *Lock;
Bitmap->Lock(&Rect, WICBitmapLockRead, &Lock);
unsigned int PixelDataSize = 0;
unsigned char *PixelData;
Lock->GetDataPointer(&PixelDataSize, &PixelData);
memcpy(Dest, PixelData, MIN(DestSize, PixelDataSize));
Stream->Release();
BitmapDecoder->Release();
FrameDecode->Release();
FormatConverter->Release();
Bitmap->Release();
Lock->Release();
}
int
main()
{
int ImageWidth = 640;
int ImageHeight = 480;
int DecodedBufferSize = ImageWidth * ImageHeight * 3;
void *DecodedBuffer = malloc(DecodedBufferSize);
FILE *ImageFile = fopen("test.jpg", "rb");
fseek(ImageFile, 0, SEEK_END);
int ImageSize = ftell(ImageFile);
rewind(ImageFile);
void *ImageData = malloc(ImageSize);
fread(ImageData, 1, ImageSize, ImageFile);
fclose(ImageFile);
Win32DecodeJpeg(ImageSize, ImageData, DecodedBufferSize, DecodedBuffer);
}
编辑:应大众需求,这里有一个具有基本错误检查和一些基本解释的版本:
#include <Wincodec.h>
#include <stdio.h>
#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Windowscodecs.lib")
void
Win32DecodeJpeg(unsigned int ImageDataSize, void *ImageData,
unsigned int DestSize, void *Dest)
{
// IWICImagingFactory is a structure containing the function pointers of the WIC API
static IWICImagingFactory *IWICFactory;
if(IWICFactory == NULL)
{
if(CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK)
{
printf("failed to initialize the COM library\n");
return;
}
if(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&IWICFactory)) != S_OK)
{
printf("failed to create an instance of WIC\n");
return;
}
}
IWICStream *Stream;
if(IWICFactory->CreateStream(&Stream) != S_OK)
{
printf("failed to create stream\n");
return;
}
if(Stream->InitializeFromMemory((unsigned char *)ImageData, ImageDataSize) != S_OK)
{
printf("failed to initialize stream from memory\n");
return;
}
IWICBitmapDecoder *BitmapDecoder;
if(IWICFactory->CreateDecoderFromStream(Stream, NULL, WICDecodeMetadataCacheOnDemand, &BitmapDecoder) != S_OK)
{
printf("failed to create bitmap decoder from stream\n");
return;
}
IWICBitmapFrameDecode *FrameDecode;
// frames apply mostly to GIFs and other animated media. JPEGs just have a single frame.
if(BitmapDecoder->GetFrame(0, &FrameDecode) != S_OK)
{
printf("failed to get 0th frame from frame decoder\n");
return;
}
IWICFormatConverter *FormatConverter;
if(IWICFactory->CreateFormatConverter(&FormatConverter) != S_OK)
{
printf("failed to create format converter\n");
return;
}
// this function does not do any actual decoding
if(FormatConverter->Initialize(FrameDecode,
GUID_WICPixelFormat24bppBGR,
WICBitmapDitherTypeNone,
nullptr,
0.0f,
WICBitmapPaletteTypeCustom) != S_OK)
{
printf("failed to initialize format converter\n");
return;
}
IWICBitmap *Bitmap;
if(IWICFactory->CreateBitmapFromSource(FormatConverter, WICBitmapCacheOnDemand, &Bitmap) != S_OK)
{
printf("failed to create bitmap from format converter\n");
return;
}
unsigned int Width, Height;
if(Bitmap->GetSize(&Width, &Height) != S_OK)
{
printf("failed to get the size of the bitmap\n");
return;
}
WICRect Rect = {0, 0, (int)Width, (int)Height};
IWICBitmapLock *Lock;
// this is the function that does the actual decoding. seems like they defer the decoding until it's actually needed
if(Bitmap->Lock(&Rect, WICBitmapLockRead, &Lock) != S_OK)
{
printf("failed to lock bitmap\n");
return;
}
unsigned int PixelDataSize = 0;
unsigned char *PixelData;
if(Lock->GetDataPointer(&PixelDataSize, &PixelData) != S_OK)
{
printf("failed to get data pointer\n");
return;
}
memcpy(Dest, PixelData, DestSize < PixelDataSize ? DestSize : PixelDataSize);
Stream->Release();
BitmapDecoder->Release();
FrameDecode->Release();
FormatConverter->Release();
Bitmap->Release();
Lock->Release();
}
int
main()
{
int ImageWidth = 640;
int ImageHeight = 480;
int DecodedBufferSize = ImageWidth * ImageHeight * 3;
void *DecodedBuffer = malloc(DecodedBufferSize);
FILE *ImageFile = fopen("test.jpg", "rb");
fseek(ImageFile, 0, SEEK_END);
int ImageSize = ftell(ImageFile);
rewind(ImageFile);
void *ImageData = malloc(ImageSize);
fread(ImageData, 1, ImageSize, ImageFile);
fclose(ImageFile);
Win32DecodeJpeg(ImageSize, ImageData, DecodedBufferSize, DecodedBuffer);
}
我有一块内存包含 JPEG 的原始字节,我想将其转换为 24 位 RGB,以便我可以使用 StretchDIBits 渲染它。我环顾了 msdn,但是天哪……我真的不想使用任何第三方库,如果不需要的话,甚至不想使用 C++。有什么建议么?我希望只有一些函数,比如 DecodeJpeg()
之类的...
我想出了一个使用 WIC 的解决方案,它似乎没有使用 C++,但我无法将以下代码编译为 C,所以不确定。花了很多时间将各个部分拼凑在一起,但就是这样!
#include <Wincodec.h>
#include <stdio.h>
#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Windowscodecs.lib")
#define MIN(A, B) (A < B ? A : B)
void
Win32DecodeJpeg(unsigned int ImageDataSize, void *ImageData,
unsigned int DestSize, void *Dest)
{
static IWICImagingFactory *IWICFactory;
if(IWICFactory == NULL)
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&IWICFactory));
}
IWICStream *Stream;
IWICFactory->CreateStream(&Stream);
Stream->InitializeFromMemory((unsigned char *)ImageData, ImageDataSize);
IWICBitmapDecoder *BitmapDecoder;
IWICFactory->CreateDecoderFromStream(Stream, NULL, WICDecodeMetadataCacheOnDemand, &BitmapDecoder);
IWICBitmapFrameDecode *FrameDecode;
BitmapDecoder->GetFrame(0, &FrameDecode);
IWICFormatConverter *FormatConverter;
IWICFactory->CreateFormatConverter(&FormatConverter);
FormatConverter->Initialize(FrameDecode,
GUID_WICPixelFormat24bppBGR,
WICBitmapDitherTypeNone,
nullptr,
0.0f,
WICBitmapPaletteTypeCustom);
IWICBitmap *Bitmap;
IWICFactory->CreateBitmapFromSource(FormatConverter, WICBitmapCacheOnDemand, &Bitmap);
unsigned int Width, Height;
Bitmap->GetSize(&Width, &Height);
WICRect Rect = {0, 0, (int)Width, (int)Height};
IWICBitmapLock *Lock;
Bitmap->Lock(&Rect, WICBitmapLockRead, &Lock);
unsigned int PixelDataSize = 0;
unsigned char *PixelData;
Lock->GetDataPointer(&PixelDataSize, &PixelData);
memcpy(Dest, PixelData, MIN(DestSize, PixelDataSize));
Stream->Release();
BitmapDecoder->Release();
FrameDecode->Release();
FormatConverter->Release();
Bitmap->Release();
Lock->Release();
}
int
main()
{
int ImageWidth = 640;
int ImageHeight = 480;
int DecodedBufferSize = ImageWidth * ImageHeight * 3;
void *DecodedBuffer = malloc(DecodedBufferSize);
FILE *ImageFile = fopen("test.jpg", "rb");
fseek(ImageFile, 0, SEEK_END);
int ImageSize = ftell(ImageFile);
rewind(ImageFile);
void *ImageData = malloc(ImageSize);
fread(ImageData, 1, ImageSize, ImageFile);
fclose(ImageFile);
Win32DecodeJpeg(ImageSize, ImageData, DecodedBufferSize, DecodedBuffer);
}
编辑:应大众需求,这里有一个具有基本错误检查和一些基本解释的版本:
#include <Wincodec.h>
#include <stdio.h>
#pragma comment(lib, "Ole32.lib")
#pragma comment(lib, "Windowscodecs.lib")
void
Win32DecodeJpeg(unsigned int ImageDataSize, void *ImageData,
unsigned int DestSize, void *Dest)
{
// IWICImagingFactory is a structure containing the function pointers of the WIC API
static IWICImagingFactory *IWICFactory;
if(IWICFactory == NULL)
{
if(CoInitializeEx(NULL, COINIT_MULTITHREADED) != S_OK)
{
printf("failed to initialize the COM library\n");
return;
}
if(CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&IWICFactory)) != S_OK)
{
printf("failed to create an instance of WIC\n");
return;
}
}
IWICStream *Stream;
if(IWICFactory->CreateStream(&Stream) != S_OK)
{
printf("failed to create stream\n");
return;
}
if(Stream->InitializeFromMemory((unsigned char *)ImageData, ImageDataSize) != S_OK)
{
printf("failed to initialize stream from memory\n");
return;
}
IWICBitmapDecoder *BitmapDecoder;
if(IWICFactory->CreateDecoderFromStream(Stream, NULL, WICDecodeMetadataCacheOnDemand, &BitmapDecoder) != S_OK)
{
printf("failed to create bitmap decoder from stream\n");
return;
}
IWICBitmapFrameDecode *FrameDecode;
// frames apply mostly to GIFs and other animated media. JPEGs just have a single frame.
if(BitmapDecoder->GetFrame(0, &FrameDecode) != S_OK)
{
printf("failed to get 0th frame from frame decoder\n");
return;
}
IWICFormatConverter *FormatConverter;
if(IWICFactory->CreateFormatConverter(&FormatConverter) != S_OK)
{
printf("failed to create format converter\n");
return;
}
// this function does not do any actual decoding
if(FormatConverter->Initialize(FrameDecode,
GUID_WICPixelFormat24bppBGR,
WICBitmapDitherTypeNone,
nullptr,
0.0f,
WICBitmapPaletteTypeCustom) != S_OK)
{
printf("failed to initialize format converter\n");
return;
}
IWICBitmap *Bitmap;
if(IWICFactory->CreateBitmapFromSource(FormatConverter, WICBitmapCacheOnDemand, &Bitmap) != S_OK)
{
printf("failed to create bitmap from format converter\n");
return;
}
unsigned int Width, Height;
if(Bitmap->GetSize(&Width, &Height) != S_OK)
{
printf("failed to get the size of the bitmap\n");
return;
}
WICRect Rect = {0, 0, (int)Width, (int)Height};
IWICBitmapLock *Lock;
// this is the function that does the actual decoding. seems like they defer the decoding until it's actually needed
if(Bitmap->Lock(&Rect, WICBitmapLockRead, &Lock) != S_OK)
{
printf("failed to lock bitmap\n");
return;
}
unsigned int PixelDataSize = 0;
unsigned char *PixelData;
if(Lock->GetDataPointer(&PixelDataSize, &PixelData) != S_OK)
{
printf("failed to get data pointer\n");
return;
}
memcpy(Dest, PixelData, DestSize < PixelDataSize ? DestSize : PixelDataSize);
Stream->Release();
BitmapDecoder->Release();
FrameDecode->Release();
FormatConverter->Release();
Bitmap->Release();
Lock->Release();
}
int
main()
{
int ImageWidth = 640;
int ImageHeight = 480;
int DecodedBufferSize = ImageWidth * ImageHeight * 3;
void *DecodedBuffer = malloc(DecodedBufferSize);
FILE *ImageFile = fopen("test.jpg", "rb");
fseek(ImageFile, 0, SEEK_END);
int ImageSize = ftell(ImageFile);
rewind(ImageFile);
void *ImageData = malloc(ImageSize);
fread(ImageData, 1, ImageSize, ImageFile);
fclose(ImageFile);
Win32DecodeJpeg(ImageSize, ImageData, DecodedBufferSize, DecodedBuffer);
}