|
|
Loading JPEGs to DirectDraw Surfaces
by Johnny Wood
译 windeer
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对象,我们可以通过检测jerr的值是否为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对象的JPEGFile成员设置成一个文件名,然后调用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.
最开始的ijlread用我们想要载入的文件信息填充我们的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转换到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实际存储的方
式,他们也是颠倒存放.你可以翻转它,只要将DIBHeight设为负值:
//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文件。我们用Windows API函数CreateBitmap建立我们的DIB
,不然的话,我们就只有自己将image转换成DIB,再绑定到Direct Draw表面了。
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得开心!
在sea_bug的基础上进行整理 [em4] [em4] [em4] [em4] [em4] [em4] [em4] |
|