我有一块内存包含JPEG的原始字节,并希望将其转换为24位RGB,因此我可以使用StretchDIBits进行渲染。我看了很多msdn但是jeez ...我真的不想使用任何第三方库甚至是C ++,如果我不需要的话。有什么建议?我希望有一些功能,如DecodeJpeg()
或其他......
答案 0 :(得分:3)
我想出了一个使用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);
}