65.9K
CodeProject 正在变化。 阅读更多。
Home

内存中图像压缩

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (28投票s)

2003年8月16日

3分钟阅读

viewsIcon

230962

downloadIcon

3513

内存图像压缩/解压缩

Sample Image - Sample.jpg

引言

本文旨在展示一种加载位图/jpg/tiff/gif/png(任何你可以用 GDI+ 加载的格式)然后将其转换为位图/tiff/jpg/png(任何你可以用 GDI+ 保存的格式)并保存到内存中的一种可能的方法。本文不会教你任何关于图像压缩的有用知识,因为它使用 GDI+ 来完成这项工作。此外,在尝试此示例之前,请查看 CP 上的精彩教程,了解如何在你的计算机上运行 GDI+。这里提供的解决方案非常简单易懂,但不幸的是,它不是最优的。我想问题是,我们为什么需要它呢?这个问题的答案是,如果我们偶尔在程序中执行一项操作,但不是经常执行,我们更倾向于使用简单而非最优的解决方案,而不是复杂的、最优的解决方案(显然,每个人都有自己的偏好)。此外,本文面向初学者,因此你不需要完全了解位图和图像压缩,即可理解代码(我不会阻止你以后有机会学习它们)。

背景

老实说,我没有广泛地使用这段代码。这段代码是在我参考 MSDN 查找我一段时间没用过的某个函数时创建的。然后我遇到了函数 CreateStreamOnHGlobal(...) ,它立刻提醒我,我们可以将 GDI+ 位图对象保存到 IStream 对象。于是我再次把注意力从原来的项目上转移开了,甚至在我意识到之前,我已经在编写代码来验证这一事实了。此外,我记得很多次,当我在 CP 上阅读论坛时,我遇到了关于如何将图像压缩到内存中的问题。

使用代码

嗯,正如你所看到的,它并没有太多内容。有一个你可以复制并粘贴到你的代码中的单一函数。但在你使用它之前,你必须在你的应用程序中链接并启动 GDI+。同样,CP 上也有关于如何执行此操作的精彩教程。

// load image
Image image(L"Nice.bmp");

// Create stream with 0 size
IStream* pIStream    = NULL;
if(CreateStreamOnHGlobal(NULL, TRUE, (LPSTREAM*)&pIStream) != S_OK)
{
    AfxMessageBox(_T("Failed to create stream on global memory!"));
    return;
}

// Get encoder class id for jpg compression
// for other compressions use
//    image/bmp
//    image/jpeg
//    image/gif
//    image/tiff
//    image/png

CLSID pngClsid;
GetEncoderClsid(L"image/jpeg", &pngClsid);

// Setup encoder parameters
EncoderParameters encoderParameters;
encoderParameters.Count = 1;
encoderParameters.Parameter[0].Guid = EncoderQuality;
encoderParameters.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParameters.Parameter[0].NumberOfValues = 1;

// setup compression level
ULONG quality = 50;
encoderParameters.Parameter[0].Value = &quality;

//  Save the image to the stream
Status SaveStatus = image.Save(pIStream, &pngClsid, &encoderParameters);
if(SaveStatus != Ok)
{
    // this should free global memory used by the stream
    // according to MSDN
    pIStream->Release();
    AfxMessageBox(_T("Failed to save to stream!"));
    return;
}

// get the size of the stream
ULARGE_INTEGER ulnSize;
LARGE_INTEGER lnOffset;
lnOffset.QuadPart = 0;
if(pIStream->Seek(lnOffset, STREAM_SEEK_END, &ulnSize) != S_OK)
{
    pIStream->Release();
    AfxMessageBox(_T("Failed to get the size of the stream!"));
    return;
}

// now move the pointer to the beginning of the file
if(pIStream->Seek(lnOffset, STREAM_SEEK_SET, NULL) != S_OK)
{
    pIStream->Release();
    AfxMessageBox(_T("Failed to move the file pointer to "
        "the beginning of the stream!"));
    return;
}

// here you can do what ever you want
/*
    1. You can use global memory
        HGLOBAL hg;
        if(GetHGlobalFromStream(pIStream, &hg) = S_OK)
        ... use hg for something

        2. Copy it into some other buffer
        char *pBuff = new char[ulnSize.QuadPart];

        // Read the stream directly into the buffer
        ULONG ulBytesRead;
        if(pIStream->Read(pBuff, ulnSize.QuadPart, &ulBytesRead) != S_OK)
        {
            pIStream->Release();
            return;
        }
*/

// I am going to save it to the file just so we can 
// load the jpg to a gfx program
CFile fFile;
if(fFile.Open(_T("test.jpg"), CFile::modeCreate | CFile::modeWrite))
{
    char *pBuff = new char[ulnSize.QuadPart];

    // Read the stream directly into the buffer
    ULONG ulBytesRead;
    if(pIStream->Read(pBuff, ulnSize.QuadPart, &ulBytesRead) != S_OK)
    {
        pIStream->Release();
        delete pBuff;
        return;
    }

    fFile.Write(pBuff, ulBytesRead);
    fFile.Close();
    delete pBuff;
}
else AfxMessageBox(_T("Failed to save data to the disk!"));

// Free memory used by the stream
pIStream->Release();

代码非常简单。首先,我加载图像,在这种情况下是 Nice.bmp。然后,我必须构造 IStream 对象,我们将使用它来将图像保存到其中。我们还需要设置图像编码器。请参考 MSDN 了解编码器参数的详细说明以及 GetEncoderClassID 函数。然后我们就可以保存了,一旦我们成功保存了数据,我们就可以使用流,它包含压缩后的图像,就像它在磁盘上一样。为了证明我正在将这些字节保存到磁盘上,以便我们可以将其加载到图形程序中。演示代码包含 nice.bmp,它是由演示软件压缩的。压缩后的图像应该在 MemImage 示例源代码文件夹中。

结论

如有任何问题、建议等,请与我联系,我将尽快尝试回复。此外,英语是我的第三语言,因此请随时给我提供改进写作技巧的建议。请记住,我不是 GDI+ 专家,我也不经常使用它。玩得开心!

许可证

本文档没有明确的许可证,但可能包含文章文本或下载文件本身的使用条款。如有疑问,请通过下方的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.