zoukankan      html  css  js  c++  java
  • Direct2D教程(九)渲染位图

    概述

    这篇的标题更确切的说应该叫位图画刷,这样才好和前几篇对应起来。在Direct2D中,位图的渲染也是通过画刷来实现的。

    Direct2D中并没有直接操作位图的接口,而是借助WIC(Windows Image Component)来完成的。今天我们来看看如何在Direct2D中加载并显示位图。这个方法可以用来渲染背景。基本步骤如下。

    • 从文件创建WIC位图
    • 由WIC位图创建D2D位图
    • 使用D2D绘制位图

    在开始之前,首先简要介绍一下WIC

    什么是WIC?

    WIC全称是Windows Image Component,是一套扩展的API,用来处理数字图像,它是基于COM组件的。该API包含非常丰富的图像处理函数,比如

    • 内置对于标准web image格式的解码支持
    • 内置对于标准metadata格式的支持
    • 广泛的像素格式支持
    • 高色度支持,包含30位扩展,30位及48位高精度像素格式
    • 对于图像解码,像素格式及元数据格式的扩展框架支持

    WIC包含的组件及每个组件中的接口如下图所示。

    在这里,我们只要知道WIC能够处理图像即可,比如位图操作。关于WIC的详细信息,大家可以看看MSDN的介绍。

    具体步骤

    从文件创建WIC位图

    给定一个图像文件,我们首先使用WIC函数将其读入内存,并创建一个WIC类型的位图。

    首先我们需要创建一个解码器,因为图片是经过编码的,为了能显示图片,我们首先需要将其解码,创建解码器需要使用函数CreateDecoderFromFilename,该函数返回一个解码器指针。稍后的操作都通过这个指针来完成,关于这个函数的详细介绍,可以参考MSDN,这里不再赘述。

    然后,利用创建好的解码器来获取图片的帧,我么这里只要第一帧,因为图片只有一帧,但是对于视频文件来说,就有许多帧了。代码如下:在这里,uri即图片文件名。

    HRESULT LoadBitmapFromFile(
                               ID2D1RenderTarget *pRenderTarget,
                               IWICImagingFactory *pIWICFactory,
                               PCWSTR uri,
                               UINT destinationWidth,
                               UINT destinationHeight,
                               ID2D1Bitmap **ppBitmap
                               )
    {
        HRESULT hr = S_OK;
    
        IWICBitmapDecoder *pDecoder = NULL;
        IWICBitmapFrameDecode *pSource = NULL;
        IWICStream *pStream = NULL;
        IWICFormatConverter *pConverter = NULL;
        IWICBitmapScaler *pScaler = NULL;
    
        hr = pIWICFactory->CreateDecoderFromFilename(
            uri,
            NULL,
            GENERIC_READ,
            WICDecodeMetadataCacheOnLoad,
            &pDecoder
            );
        if (SUCCEEDED(hr))
        {
    
            // Create the initial frame.
            hr = pDecoder->GetFrame(0, &pSource);
        }

    然后创建converter,负责对位图进行后续的格式转换。

    if (SUCCEEDED(hr))
    {
        hr = pIWICFactory->CreateFormatConverter(&pConverter);
    }

    接下来则要判断图像是否被放大或者缩小了,比如一个图片的原始尺寸是100 x 100,但是我们程序中要以 200 x 200的方式去显示,那么相当于将图片放大了一倍,图片的显示尺寸通过参数来指定,而实际尺寸则是通过分析图片文件得到。如果图片有缩放,那么需要从新生成图片的数据文件,如果没有,那么直接进行下一步即可。代码如下:

    // If a new width or height was specified, create an
    // IWICBitmapScaler and use it to resize the image.
    if (destinationWidth != 0 || destinationHeight != 0)
    {
        UINT originalWidth, originalHeight;
        hr = pSource->GetSize(&originalWidth, &originalHeight);
        if (SUCCEEDED(hr))
        {
            if (destinationWidth == 0)
            {
                FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
                destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
            }
            else if (destinationHeight == 0)
            {
                FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
                destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
            }
    
            hr = pIWICFactory->CreateBitmapScaler(&pScaler);
            if (SUCCEEDED(hr))
            {
                hr = pScaler->Initialize(
                    pSource,
                    destinationWidth,
                    destinationHeight,
                    WICBitmapInterpolationModeCubic
                    );
            }
            if (SUCCEEDED(hr))
            {
                hr = pConverter->Initialize(
                    pScaler,
                    GUID_WICPixelFormat32bppPBGRA,
                    WICBitmapDitherTypeNone,
                    NULL,
                    0.f,
                    WICBitmapPaletteTypeMedianCut
                    );
            }
        }
    }

    由WIC位图创建D2D位图

    调用函数CreateBitmapFromWicBitmap可以由一个WIC位图创建一个D2D位图,代码如下:

    if (SUCCEEDED(hr))
    {
        // Create a Direct2D bitmap from the WIC bitmap.
        hr = pRenderTarget->CreateBitmapFromWicBitmap(
            pConverter,
            NULL,
            ppBitmap
            );
    }

    上面这些代码有个特点,就是要时刻判断前一次函数调用的返回值,只有前面的操作成功了,才进行下一步操作。这是很好的编程习惯。

    最后,需要做一些清理工作,由于WIC是基于COM的,所以,需要手动释放COM对象,代码如下:

    SAFE_RELEASE(pDecoder);
    SAFE_RELEASE(pSource);
    SAFE_RELEASE(pStream);
    SAFE_RELEASE(pConverter);
    SAFE_RELEASE(pScaler);

    SAFE_RELEASE是一个宏定义

    #define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}

    使用D2D绘制位图

    这一步就很简单了,绘制位图和绘制其他几何图形几乎没有区别。首先是将render target清空为指定颜色,也就是背景色,然后调用render target的接口DrawBitmap来绘制位图,这个函数需要指定位图的尺寸,所以之前还需要获取位图的大小。注意绘制代码要放在BeginDraw和EndDraw之间。

    void DrawBitmap()
    {
        CreateD2DResource(g_Hwnd) ;
    
        pRenderTarget->BeginDraw() ;
    
        // Clear background color to dark cyan
        pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    
        D2D1_SIZE_F size = pBitmap->GetSize() ;
        D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;
    
        // Draw bitmap
        pRenderTarget->DrawBitmap(
            pBitmap,
            D2D1::RectF(
            upperLeftCorner.x,
            upperLeftCorner.y,
            upperLeftCorner.x + size.width,
            upperLeftCorner.y + size.height)
            ) ;
    
        HRESULT hr = pRenderTarget->EndDraw() ;
        if (FAILED(hr))
        {
            MessageBox(NULL, "Draw failed!", "Error", 0) ;
    
            return ;
        }
    }

    最后,来一张效果图,这是微软的游戏 4 Elements 2 的截图,大家一同欣赏一下。这是我平生购买的第一款游戏,值得纪念一下。

    ==

    Happy Coding!!! 永远不要放弃自己的梦想。

    作者:zdd
    出处:http://www.cnblogs.com/graphics/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    JS之Math用法
    思科路由器的内存体系由多种存储设备组成,其中用来存放IOS引导等程序的是(11),运行时活动配置文件存放在(12)中。
    下图是一个软件项目的活动图,其中顶点表示项目里程碑,连接顶点的边表示活动,边的权重表示活动的持续时间,则里程碑(7)在关键路径上,活动GH的松弛时间是(8)。
    内存按字节编址从A5000H到DCFFFH的区域其存储容量为(2)。
    若用256K×8bit的存储器芯片,构成地址40000000H到400FFFFFH且按字节编址的内存区域,则需(5)片芯片。
    假设网络的生产管理系统采用B/S工作方式,经常上网的用户数为100个,每个用户每分钟平均产生11个事务,平均事务量大小为0.06MB,则这个系统需要的传输速率为(34)。
    数据包在电缆中的传输时间
    判断一个字符串是否被Base64加密
    bugku之杂项---闪的好快
    关于用jQuery的animate方法实现的动画在IE中失效的原因以及解决方法
  • 原文地址:https://www.cnblogs.com/graphics/p/2764869.html
Copyright © 2011-2022 走看看