c++ - 高级 Win32 图像文件 I/O?

标签 c++ windows image winapi io

我想在 Windows C++ 应用程序中将图像文件读入内存。什么是一个相当简单的解决方案,也许类似于 IOS 在 UIImage 中提供的解决方案?

我希望支持合理数量的文件格式。

我需要对位图进行一些低级访问以进行图像处理。

我在互联网上阅读了很多内容,看起来 Windows DIB 可能是一个合理的内存表示。除此之外,我找不到示例代码来将 JPEG 或 PNG 读取到内存中的 DIB 中。

感谢您的任何建议。

最佳答案

我刚刚检查了 LoadImage 确实支持通过标志 LR_LOADFROMFILE 从文件加载.

所以这将是我的第一选择。

第二选择,GDI+(请注意,它需要大量摆弄初始化内容才能获得普通的良好质量,并且至少几年前它仍然依赖 minmax 来自 <windows.h> )。第三个选择,Windows Imaging Component在对该问题的评论中提到。第四个选择, OleLoadPicturePath 和家人。


附录:如评论 LoadImage 中所述仅限于加载图像文件的“位图”。在我的系统上,下面的测试程序报告 .bmp 文件加载正常,但 .gif、.png 和 .jpg 文件加载失败。

#undef UNICODE
#define UNICODE
#include <windows.h>

#include <assert.h>         // assert
#include <iostream>         // std::wcout
#include <string>           // std::wstring
using namespace std;

auto get_exe_path()
    -> wstring
{
    int const buffer_size = MAX_PATH;
    wstring result( buffer_size, L'#' );
    int const n_characters = GetModuleFileName( 0, &result[0], buffer_size );
    assert( 0 < n_characters && n_characters < buffer_size );
    result.resize( n_characters );
    return result;
}

auto get_exe_folder_path()
    -> wstring
{
    wstring const exe_path = get_exe_path();
    int const i = exe_path.rfind( L'\\' );
    return exe_path.substr( 0, i + 1 );
}

void test( wstring const& image_name )
{
    wstring const image_file_name = get_exe_folder_path() + image_name;
    wcout << image_file_name << endl;
    HANDLE const image = ::LoadImage(
        0,              // HINSTANCE hinst,
        image_file_name.c_str(),
        IMAGE_BITMAP,
        0, 0,   // int cxDesired, int cyDesired,
        LR_LOADFROMFILE
        );
    wcout << image << endl;
    DeleteObject( image );
}

auto main()
    -> int
{
    test( L"test.bmp" );  wcout << endl;
    test( L"test.png" );  wcout << endl;
    test( L"test.gif" );  wcout << endl;
    test( L"test.jpg" );
}

附录 2:为了检查一下,我还测试了 Windows 成像组件功能,它确实可以处理上述所有四种图像类型。下面代码的大部分大小是由于对 COM 的可重用一次写入支持(我只是再次从头开始编写它,所以它有点粗略,只是这里需要的)。不过,此代码不会显示图像或对其执行任何其他操作,而 WIC 也同样复杂......

尽管此代码具有部分 g++ 支持,但我尚未使用 g++ 对其进行了测试。我记得 g++ 仅支持 Windows API,就像 Windows XP 一样。我不确定 WIC 何时引入(尽管它可以与 Windows XP 一起使用)。

#undef UNICODE
#define UNICODE
#include <windows.h>
#include <wincodec.h>       // IWICImagingFactory

#include <algorithm>        // std::swap
#include <assert.h>         // assert
#include <iostream>         // std::wcout
#include <stdlib.h>         // EXIT_FAILURE, EXIT_SUCCESS
#include <string>           // std::string, std::wstring
#include <utility>          // std::move

#ifndef CPPX_NOEXCEPT
#   if defined( _MSC_VER )
#       define CPPX_NOEXCEPT   throw()
#   else
#       define  CPPX_NOEXCEPT   noexcept
#   endif
#endif

#ifndef CPPX_NORETURN
#   if defined( _MSC_VER )
#       define CPPX_NORETURN   __declspec( noreturn )
#       pragma warning( disable: 4646 )     // "has non-void return type"
#   elif defined( __GNUC__ )
#       define CPPX_NORETURN    __attribute__((noreturn))
#   else
#       define CPPX_NORETURN    [[noreturn]]
#   endif
#endif

namespace cppx {
    using std::string;
    using std::runtime_error;

    auto hopefully( bool const condition )
        CPPX_NOEXCEPT
        -> bool
    { return condition; }

    CPPX_NORETURN
    auto fail( string const& s )
        -> bool
    { throw runtime_error( s ); }
}  // namespace cppx

namespace process {
    using std::wstring;

    auto get_exe_path()
        -> wstring
    {
        int const buffer_size = MAX_PATH;
        wstring result( buffer_size, L'#' );
        int const n_characters = GetModuleFileName( 0, &result[0], buffer_size );
        assert( 0 < n_characters && n_characters < buffer_size );
        result.resize( n_characters );
        return result;
    }

    auto get_exe_folder_path()
        -> wstring
    {
        wstring const exe_path = get_exe_path();
        int const i = exe_path.rfind( L'\\' );
        return exe_path.substr( 0, i + 1 );
    }
}  // namespace process

namespace com {
    using cppx::fail;
    using std::move;

    enum Success { success };

    auto operator>>( HRESULT const hr, Success )
        -> bool
    { return SUCCEEDED( hr ); }

    struct Library
    {
        ~Library()
        { CoUninitialize(); }

        Library()
        { CoInitialize( nullptr ); }
    };

    template< class Interface >
    class Ptr
    {
    private:
        Interface*  p_;

    public:
        auto raw() -> Interface* { return p_; }
        auto operator->() -> Interface* { return p_; }

        void clear() { Ptr null; swap( *this, null ); }

        auto as_value_receiver()
            -> Interface**
        {
            clear();
            return &p_;
        }

        auto as_untyped_value_receiver()
            -> void**
        { return reinterpret_cast<void**>( as_value_receiver() ); }

        friend void swap( Ptr& a, Ptr& b )
            CPPX_NOEXCEPT
        { std::swap( a.p_, b.p_ ); }

        void operator=( Ptr other )
        { swap( *this, other ); }

        void operator=( Ptr&& other )
        {
            Ptr temp( move( other ) );
            swap( temp, *this );
        }

        ~Ptr()
        { if( p_ != nullptr ) { p_->Release(); } }

        explicit Ptr( Interface* p = nullptr )
            CPPX_NOEXCEPT
            : p_( p )
        {}

        Ptr( Ptr const& other )
            : p_( other.p_ )
        { if( p != nullptr ) { p_->AddRef(); } }

        Ptr( Ptr&& other )
            CPPX_NOEXCEPT
            : p_( other.p_ )
        { other.p_ = nullptr; }

        static
        auto create_local( CLSID const& class_id )
            -> Ptr<Interface>
        {
            Ptr<Interface>  result;
            ::CoCreateInstance(
                class_id, nullptr, CLSCTX_INPROC_SERVER,
                __uuidof( Interface ),
                result.as_untyped_value_receiver()
                )
                >> success
                || fail( "CoCreateInstance" );
            return move( result );
        }
    };

}  // namespace com

namespace app {
    using cppx::fail;
    using std::wstring;
    using std::wcout; using std::endl;

    void test( wstring const& image_name )
    {
        wstring const image_file_name =
            process::get_exe_folder_path() + image_name;
        wcout << image_file_name << endl;

        auto                            p_factory   =
            com::Ptr<IWICImagingFactory>::create_local( CLSID_WICImagingFactory );

        com::Ptr< IWICBitmapDecoder>    p_decoder;
        p_factory->CreateDecoderFromFilename(
            image_file_name.c_str(),
            nullptr,
            GENERIC_READ,
            WICDecodeMetadataCacheOnDemand, // Cache metadata when needed
            p_decoder.as_value_receiver()
            )
            >> com::success
            || fail( "IWICImagingFactory::CreateDecoderFromFilename" );

        com::Ptr<IWICBitmapFrameDecode> p_frame;
        p_decoder->GetFrame( 0, p_frame.as_value_receiver() )
            >> com::success
            || fail( "IWICBitmapFrameDecode::GetFrame");

        UINT w, h;
        p_frame->GetSize( &w, &h )
            >> com::success
            || fail( "IWICBitmapFrameDecode::GetSize" );

        wcout << "(w, h) = (" << w << ", " << h << ")" << endl;
    }

    void cpp_main()
    {
        com::Library const  com_usage;

        test( L"test.bmp" );  wcout << endl;
        test( L"test.png" );  wcout << endl;
        test( L"test.gif" );  wcout << endl;
        test( L"test.jpg" );  wcout << endl;
        test( L"test.bogus" );
    }
}  // namespace app

auto main()
    -> int
{
    using namespace std;
    try
    {
        app::cpp_main();
        return EXIT_SUCCESS;
    }
    catch( exception const& x )
    {
        wcout << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}

关于c++ - 高级 Win32 图像文件 I/O?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23496264/

相关文章:

c++ - 将多个函数存储到数组 C++ 中以进行循环

C++赋值运算符关于继承的问题

c++ - 使用同一个 DLL 的多个版本

windows - 代码的不同行为(是否调试和不同的计算机)

ios - 重复UITextView的背景图片?

javascript - 如何在图像上定义自定义选择/ mask (上传后立即在线脚本)

c++ - 如何定义采用可变类模板的函数?

c++ - 四向等价

根本无法使用 Windows Driver Kit 构建环境声明变量

html - 如何将其中一个相机图像插入到 html 元素中——输入?