载入JPGE图象文件到DirectDraw的表面中

Loading JPEGs to DirectDraw Surfaces 
载入JPGE图象文件到DirectDraw的表面中

by Johnny Wood
译: sea_bug

译者的话:这是一篇关于使用Intel JPGEs Library的文章,在翻译的同时,译者根据自己的使用经验对文章进行适当的添减章节,希望适合各位读者。

In order to keep the size of this article down, I've decided to make a few assumptions. First of all, I assume that you already know C/C++ and how to troubleshoot and debug code. I also assume that you are somewhat familiar with DirectDraw and that you have as a minimum the DirectX 7.0 libraries and the ability to work in 24 bit. Note: the source code in EXAMPLE.ZIP available at the end of this article provides conversions to 16bit and 32bit surfaces. 
为了保持这篇文章内的排列顺序,我先决定安排一些假设。首先,我假设你已经了解C/C++与如何对代码进行调试。我还假设你对DirectDraw有些了解与你拿到了DirectX 7.0的库文件,并且能够在24bit的情况下工作。注意:本文章附带的原代码 EXAMPLE.ZIP 中提供转换到16bit和32bit表面的操作。


The first step to loading JPEGs is to download the Intel JPEG Library from Intel's website. The Library is loaded with documentation and examples, all of which we're really not interested in. What we really want are the IJL.H, IJL15.LIB, and IJL15.DLL files that come with the package. Once you have those files, include the IJL.H header to 
your source file, add the IJL15.LIB file to your project, and make sure the IJL15.DLL is in a valid location such as the C:/WINDOWS/SYSTEM folder. 

要载入JPGE图象文件首先要Intel的网站上去下载Intel JPEG Library,这个库包含了开发文档和例程,以及你不感兴趣的东西。我们真正要的是IJL.H,IJL15.LIB,和IJL15.DLL文件。一旦你拥有了这些文件,包含IJL.H头文件到你的代码文件中,添加IJL15.LIB文件到你的工程,并且确定IJL15.DLL文件是在有效的位置,如C:/Windows/Sysstem文件夹,当然,也可以跟我们编译出来的程式执行档放置于同一文件夹。


There are a few more things we need to do before beginning. We need to make sure that we have a Direct Draw Surface to work with:
有些东西需要我们在开始之前先准备好,我们需要确定我们拥有可工作的DirectDraw表面:

LPDIRECTDRAWSURFACE7 Surface = NULL;

We need to also be sure to set our display bit depth to 24 bit: 
我们还需要设置我们的视频模式,深度为24bit:

DDObject->SetDisplayMode(640, 480, 24, 0, 0);

We're now ready to load a JPEG to our surface. Since we're using the Intel JPEG Library, we need to create a couple of objects: 
我们现在准备载入JPEG图象到我们的表面,既然我们要使用Intel JPEG Library,我们需要建立一个连接对象:

IJLERR jerr;
JPEG_CORE_PROPERTIES jcprops;


IJLERR holds return information for determining a pass or fail status. 
JPEG_CORE_PROPERTIES is our JPEG object. Once we have these two objects, we are ready to initialize them: 

IJLERR保存返回的终止或错误属性信息。
JPEG_CORE_PROPERTIES是我们的JPEG对象,一旦我们有这两个对象,我们准备对其进行初始化:


jerr = ijlInit(&jcprops);
if (jerr != IJL_OK)
    //report initialization error


The ijlInit function call initializes the JPEG_CORE_PROPERTIES object. We can check the status of this function call by testing whether or not our IJLERR object was initialized with the value IJL_OK. 
ijlInit函数调用初始化JPEG_CORE_PROPERTIES对象,我们能检测这个函数调用测试我们的IJLERR对象是否初始化属性是否为IJL_OK。

At this point, we must decide if we are going to load our JPEG image from a file or from a buffer. Because loading from a file takes fewer steps, we will do that here. However, I give an example of loading from both in the EXAMPLE.ZIP file available at the end of this article. We load from a file by changing our JPEG object's JPGFile member to a file name. We then call ijlRead to retrieve the file parameters. 
在这点,我们必须决定我们是从文件载入我们的JPEG图象,还是从数据缓冲。因为从文件载入所需的步骤较少,我们将用这方法。无论如何,在文章的例子EXAMPLE.ZIP中,我会给出两种可用的的方法。我们从文件中载入并转换我们的JPEG对象的JPG文件成员到一个文件名,我们当调用ijlRead函数可以重新获得文件参数。

jcprops.JPGFile = FileName;
jerr = ijlRead(&jcprops, IJL_JFILE_READPARAMS);
if (jerr != IJL_OK)
    //report read error


This initial read fills our JPEG object with information about the file we are going to load. What we must now do is find a way of converting the JPEG to a device independent bitmap (DIB) so that we can attach it to our Direct Draw surface. 
这初始指定我们的JPGE对象的文件名,我们将根据这个进行载入。我们现在必须寻找一个转换的方式用于JPGE设备与bitmap(BID),因此我们能绑定它到我们的DirectDraw表面。

We start by creating a buffer to hold our image data. After the buffer is created, we must resize it to fit a 24Bit image: 
我们开始建立一个缓冲为保存我们的位图数据,在这个缓冲建立之后,我们必须调整大小以适合一个24bit的位图:

//Prepare a 24Bit buffer to receive image data
BYTE *buffer24;

//Determine the required size
long szbuff24 = (jcprops.JPGWidth * 24 + 7) / 8 * jcprops.JPGHeight;

//Resize the buffer and check for null
buffer24 = new BYTE [szbuff24];
if (buffer24 == NULL)
    //Report memory allocation error


Now we need to fill in the DIB portion of the JPEG object to get ready for the conversion from JPEG to DIB. 
现在我们需要为JPEG对象准备好转换到BID的部分进行填充。

jcprops.DIBWidth = jcprops.JPGWidth;
jcprops.DIBHeight = jcprops.JPGHeight; //Implies a bottom-up DIB.
jcprops.DIBChannels = 3;
jcprops.DIBColor = IJL_BGR;
jcprops.DIBPadBytes = IJL_DIB_PAD_BYTES(jcprops.JPGWidth, 3);
jcprops.DIBBytes = reinterpret_cast <BYTE*> (buffer24);


Let's look at some of these a little closer. The DIBBytes member points to the buffer that we created. When we retrieve the JPEG data, the information we get will be stored in this buffer. The DIBWidth and DIBHeight members specify the size of the DIB. The DIBColor member specifies that we want our image data in reverse order Blue Green Red. That's the way that DIBs are actually stored. They are also stored upside down. You can flip the retrieved image by negating the DIBHeight member: 
让我们看看这一些结构,DIBBytes成员变量指向一个我们已经建立好的数据缓冲,当我们重新获得JPEG数据,这些信息将是我们用于存储的缓冲;DIBWidth和DIBHeight成员指定DIB的大小;DIBColor成员指定我们要我们的位图数据是倒序的兰、绿、红。那是DIBs实际存储的方式,他们也是颠倒存放,你可以翻转它:

//This is what you should do if you find your images are coming out upside down.
jcprops.DIBHeight = - jcprops.JPGHeight;

Before we read in the image, we have to check one more thing: the JPG color space:
在我们读数据之前,我们还要检测其它东西:JPG颜色空间

//Set the JPG color space ... this will always be somewhat of an
//educated guess at best because JPEG is "color blind" (i.e.,
//nothing in the bit stream tells you what color space the data was
//encoded from.
switch(jcprops.JPGChannels)
{
    case 1: jcprops.JPGColor = IJL_G;
        break;

    case 3: jcprops.JPGColor = IJL_YCBCR;
        break;

    default:
        //This catches everything else, but no color twist will be
        //performed by the IJL.
        jcprops.DIBColor = (IJL_COLOR)IJL_OTHER;
        jcprops.JPGColor = (IJL_COLOR)IJL_OTHER;
        break;
}


We are finally ready to retrieve the actual JPEG image. Thanks to Intel's JPEG Library - this is a trivial task: 
我们准备最终获得JPEG图象数据,感谢Intel的JPEG库—这是一个十分简单的任务:

//Read in image from file
jerr = ijlRead(&jcprops, IJL_JFILE_READWHOLEIMAGE);
if (jerr != IJL_OK)
    //Report read error


This function copies the image information into our buffer. At this point, if we were to insert a BITMAPFILEHEADER and a BITMAPINFOHEADER at the front of our buffer, we could dump the buffer to a binary file. This would effectively create a bitmap file saved to disk. However, we instead want to turn our image into a DIB and attach it to a Direct Draw surface. Therefore, we use the Windows API function CreateBitmap to build our DIB:
这个函数拷贝位图信息到我们的缓冲,在这个地方,如果我们是插入一个BITMAPFILEHEADER或一个BITMAPINFOHEADER到我们的缓冲前面,我们可以颠倒缓冲到一个二进制文件中,这将在磁盘上建立一个有效的BMP图象文件。无论如何,我们插入要旋转我们的位图到一个DIB中,并把它关联到一个DirectDraw的表面上。因此,我们使用Windows API函数CreateBitmap建立我们的DIB:

HBITMAP hbm;

//Create the bitmap and get a handle to it
hbm = CreateBitmap (jcprops.JPGWidth, jcprops.JPGHeight, 1, 24, buffer24);
if(hbm == NULL)
    //Report failure to create bitmap


The CreateBitmap function takes the dimmensions of the image, the number of channels, the number of bits per pixel, and the color bit information from our bitmap buffer and creates a bitmap for us. Upon success, we are given a handle to the newly created bitmap. 
CreateBitmap函数的任务是为我们创建一个位图,包括通道的数量、像素的bit数量、颜色bit信息。在成功的基础上,我们获得一个新建立位图的句柄。

Before we go any further, we need to make sure that we have a Direct Draw surface to copy our bitmap to. Set up the Direct Draw surface description and create the surface: 
在我们进入更深层次之前,我们需要确认我们有一个用于我们位图拷贝的DirectDraw的表面,设置DirectDraw表面结构并且建立表面:

DDSURFACEDESC2 ddsd;

ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = jcprops.JPGWidth;
ddsd.dwHeight = jcprops.JPGHeight;

Result = DDObject->CreateSurface(&ddsd, &Surface, NULL);
if (Result != DD_OK)
    //Report surface creation error


Now, all that is left is to copy our bitmap over to our Direct Draw surface. Fortunately, there is a function provided by Direct Draw that does just that. It can be found in the DDUTILS.CPP file:
现在,拷贝我们的位图到我们的DirectDraw表面上,幸运的是,倘若在DirectDraw正好是一个函数,它能建立在DDUTILS.CPP文件里:


DDCopyBitmap(Surface, hbm, 0, 0, 0, 0);

Before we test our image out, let's clean up some things that we don't need any more:
在我们测试我们的位图前,让我们清理一些东西,那是我们不需要的:

//We no longer need our image buffer
delete buffer24;

//Release the JPEG object
ijlFree(&jcprops);

Finally, the time has come to take our image for a test drive:
最终,我们对我们的位图进行测试:

RECT Image;

//Reset surface description
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof( ddsd );

//Get the surface description so that we can dynamically
//find the width and height of our surface
Result = Surface->GetSurfaceDesc(&ddsd);
if (Result == DD_OK)
{
    //Coordinates of image size
    Image.left = 0;
    Image.top = 0;
    Image.right = ddsd.dwWidth;
    Image.bottom = ddsd.dwHeight;

    //Blit image to back buffer
    while (true)
    {
        Result = BackBuffer->BltFast (0, 0, Surface, &Image, DDBLTFAST_WAIT | DDBLTFAST_NOCOLORKEY);
        if( Result == DD_OK ) break;
        if( Result == DDERR_SURFACELOST )
        {
            Result = RestoreAll();
            if( Result != DD_OK ) break;
        }
        if( Result != DDERR_WASSTILLDRAWING ) break;
    }
}


If everything goes smoothly, you should see your image pop up on the screen. Keep in mind that you still have to release your surface when you no longer need it, and that you may have to restore it as a result of ALT+TAB. You can restore the surface by following these exact steps, however, you will not need to create the surface again. 
如果一切正常,你将要看到你的位图显示在屏幕上,当你不再需要它,你依然要释放你的表面,或者你在ALT+TAB的时候需要对表面进行恢复。你按照严格的不走就能恢复表面,当然,你将不需要再此建立表面。

Good luck, and have fun with JPEGs!
祝你好运,并希望使用JPEGs得开心!

Intel JPEG Library可以在本站中
下载,或者到Intel官方网站上下载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值