direct:载入JPEG到Direct表面



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 erested 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,  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网站WebSite上去下载Intel JPEG Library这个库包含了开发文档和例程以及你不感兴趣东西我们真正要是IJL.HIJL15.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  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  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);
 (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 po, we must decide  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);
 (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 =  BYTE [szbuff24];
 (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 = reerpret_cast <BYTE*> (buffer24);

Let's look at some of these a little closer. The DIBBytes member pos 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 

specy the size of the DIB. The DIBColor member species 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  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)
{
     1: jcprops.JPGColor = IJL_G;
        ;

     3: jcprops.JPGColor = IJL_YCBCR;
        ;

    default:
        //This catches everything , but no color twist will be


        //performed by the IJL.
        jcprops.DIBColor = (IJL_COLOR)IJL_OTHER;
        jcprops.JPGColor = (IJL_COLOR)IJL_OTHER;
        ;
}

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

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

This function copies the image information o our buffer. At this po 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 o a DIB and attach it to a Direct 

Draw surface. Therefore, we use the Windows API function CreateBitmap to build our DIB:
这个拷贝位图信息到我们缓冲在这里如果我们是插入个BITMAPFILEHEADER或个BITMAPINFOHEADER到我们缓冲前面

们可以缓冲倾泄到个 2进制文件中这就想当于磁盘上建立个BMP文件我们用Windows APICreateBitmap建立我们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);
(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 ly 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, (ddsd));
ddsd.dwSize = (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);
 (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;

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

//Get the surface de

scription so that we can dynamically
//find the width and height of our surface
Result = Surface->GetSurfaceDesc(&ddsd);
 (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);
        ( Result  DD_OK ) ;
        ( Result  DDERR_SURFACELOST )
        {
            Result = RestoreAll;
            ( Result != DD_OK ) ;
        }
        ( Result != DDERR_WASSTILLDRAWING ) ;
    }
}

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得开心!
Tags:  direct9 direct9.0 direct3d direct

延伸阅读

最新评论

发表评论