簡體   English   中英

如何使用Win32解碼JPEG?

[英]How to Decode JPEG Using Win32?

我有一塊內存包含JPEG的原始字節,並希望將其轉換為24位RGB,因此我可以使用StretchDIBits進行渲染。 我看了很多msdn但是jeez ...我真的不想使用任何第三方庫甚至是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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM