Simple Image Display

I am looking for a line(s) of code to use to display a previously saved image in a window. I am currently working in Microsoft Visual Studio 2010 Express and would prefer if the method did not involve downloading any external programs. I would be happy if the image could be displayed in either a separate window or within the console application, it does not matter (if it is in another window, it would be good if you include code to change an image within that window to another image, without actually closing that window and opening another). Also, please include any other libraries used ( #include <> ). I am using it for the purposes of making a game, I already have all of main code for the game, I am just looking for a way of displaying some kind of visuals to go along with it.
Tsk... another newbie that got sucked into the foreboding vortex of console games.

Console games are difficult to make. The console really just isn't designed with them in mind.. and any attempt to use the console to make them usually twists the console into a mockery of its primary function. Usually it's much easier to use a proper window.

It's especially difficult to add images as an afterthought. If you would have just started with a real window from day 1, you would have had a much easier time.


That said.... I've created 2 working examples for you below.

1) Using WinAPI only (only works on Windows, is slow, is clunky, and is much more confusing, but does not require any additional downloads)

2) Using SFML (crossplatform -- works on Windows, *nix, Mac... is much much faster, and is much, much easier to write, use and understand. But does require an additional download).


I know you said you didn't want to download any libs.. but you really should reconsider. Working directly with WinAPI for a game is a horrendous choice. You'll see why when you look at the code below


Each of these approaches assume the following:
- You want to create a new window that just houses the image and does nothing else
- The image is a singular static image of a fixed size that takes up the whole screen


There are ways to display the image directly to the console... but you are limited in the number of colors it will display... it will be EVEN SLOWER, even clunkier, and much, much more confusing. Plus I don't even really know how to do it.


Without further ado... here's the code. I tried to make both of these as simple as possible. I did not intentionally make the WinAPI version confusing -- WinAPI just really is that confusing:

Using WinAPI directly:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <Windows.h>

///////////////////////////////
///////////////////////////////
// I hate globals, but to keep this simple, we'll have our image stuff be global
HDC         imageDC;        // the DC to hold our image
HBITMAP     imageBmp;       // the actual bitmap which contains the image (will be put in the DC)
HBITMAP     imageBmpOld;    // the DC's old bitmap (for cleanup)

const int   screenSize_X = 640;
const int   screenSize_Y = 480;

///////////////////////////////
///////////////////////////////
// Function to load the image into our DC so we can draw it to the screen
void loadImage(const char* pathname)
{
    imageDC = CreateCompatibleDC(NULL);     // create an offscreen DC

    imageBmp = (HBITMAP)LoadImageA(         // load the bitmap from a file
            NULL,                           // not loading from a module, so this is NULL
            pathname,                       // the path we're loading from
            IMAGE_BITMAP,                   // we are loading a bitmap
            0,0,                            // don't need to specify width/height
            LR_DEFAULTSIZE | LR_LOADFROMFILE// use the default bitmap size (whatever the file is), and load it from a file
            );

    imageBmpOld = (HBITMAP)SelectObject(imageDC,imageBmp);  // put the loaded image into our DC
}


///////////////////////////////
// Function to clean up
void cleanUpImage()
{
    SelectObject(imageDC,imageBmpOld);      // put the old bmp back in our DC
    DeleteObject(imageBmp);                 // delete the bmp we loaded
    DeleteDC(imageDC);                      // delete the DC we created
}

///////////////////////////////
///////////////////////////////
// The function to draw our image to the display (the given DC is the screen DC)
void drawImage(HDC screen)
{
    BitBlt(
        screen,         // tell it we want to draw to the screen
        0,0,            // as position 0,0 (upper-left corner)
        screenSize_X,   // width of the rect to draw
        screenSize_Y,   // height of the rect
        imageDC,        // the DC to get the rect from (our image DC)
        0,0,            // take it from position 0,0 in the image DC
        SRCCOPY         // tell it to do a pixel-by-pixel copy
        );
}


///////////////////////////////
///////////////////////////////
// A callback to handle Windows messages as they happen
LRESULT CALLBACK wndProc(HWND wnd,UINT msg,WPARAM w,LPARAM l)
{
    // what kind of message is this?
    switch(msg)
    {
        // we are interested in WM_PAINT, as that is how we draw
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC screen = BeginPaint(wnd,&ps);   // Get the screen DC
            drawImage(screen);                  // draw our image to our screen DC
            EndPaint(wnd,&ps);                  // clean up
        }break;

        // we are also interested in the WM_DESTROY message, as that lets us know when to close the window
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }

    // for everything else, let the default window message handler do its thing
    return DefWindowProc(wnd,msg,w,l);
}


///////////////////////////////
///////////////////////////////
// A function to create the window and get it set up
HWND createWindow(HINSTANCE inst)
{
    WNDCLASSEX wc = {0};        // create a WNDCLASSEX struct and zero it
    wc.cbSize =         sizeof(WNDCLASSEX);     // tell windows the size of this struct
    wc.hCursor =        LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW));        // tell it to use the normal arrow cursor for this window
    wc.hInstance =      inst;                   // give it our program instance
    wc.lpfnWndProc =    wndProc;                // tell it to use our wndProc function to handle messages
    wc.lpszClassName =  TEXT("DisplayImage");   // give this window class a name.

    RegisterClassEx(&wc);           // register our window class with Windows

    // the style of the window we want... we want a normal window but do not want it resizable.
    int style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;    // normal overlapped window with a caption and a system menu (the X to close)
        
    // Figure out how big we need to make the window so that the CLIENT area (the part we will be drawing to) is
    //  the desired size
    RECT rc = {0,0,screenSize_X,screenSize_Y};      // desired rect
    AdjustWindowRect(&rc,style,FALSE);              // adjust the rect with the given style, FALSE because there is no menu

    return CreateWindow(            // create the window
        TEXT("DisplayImage"),       // the name of the window class to use for this window (the one we just registered)
        TEXT("Display an Image"),   // the text to appear on the title of the window
        style | WS_VISIBLE,         // the style of this window (OR it with WS_VISIBLE so it actually becomes visible immediately)
        100,100,                    // create it at position 100,100
        rc.right - rc.left,         // width of the window we want
        rc.bottom - rc.top,         // height of the window
        NULL,NULL,                  // no parent window, no menu
        inst,                       // our program instance
        NULL);                      // no extra parameter

}


///////////////////////////////
///////////////////////////////
// The actual entry point for the program!
//  This is Windows' version of the 'main' function:
int WINAPI WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmd,int show)
{
    // load our image
    loadImage("image.bmp");

    // create our window
    HWND wnd = createWindow(inst);

    // Do the message pump!  keep polling for messages (and respond to them)
    //  until the user closes the window.
    MSG msg;
    while( GetMessage(&msg,wnd,0,0) ) // while we are getting non-WM_QUIT messages...
    {
        TranslateMessage(&msg);     // translate them
        DispatchMessage(&msg);      // and dispatch them (our wndProc will process them)
    }

    // once the user quits....
    cleanUpImage();
}


Ran out of space... so I'll put the SFML code in a follow-up post
Using SFML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

// I'm cheating a little with this header -- you normally have to include
// SFML/Graphics.hpp and SFML/Window.hpp and link to the libs, but I just include
// this common header I made which does all that automatically
#include <sfml.h>


///////////////////////////////
///////////////////////////////

const int   screenSize_X = 640;
const int   screenSize_Y = 480;

///////////////////////////////
///////////////////////////////
// Function to load the image into our texture and sprite so we can draw it
void loadImage(const char* pathname, sf::Texture& texture, sf::Sprite& sprite)
{
    texture.loadFromFile(pathname);     // load it from the file
    sprite.setTexture(texture);         // put that texture in our sprite
    sprite.setTextureRect( sf::IntRect(0,0,screenSize_X,screenSize_Y) );    // the rectangle of the texture to use for this sprite
}

///////////////////////////////
///////////////////////////////
// Normal entry point
int main()
{
    // Create our window
    sf::RenderWindow window(
        sf::VideoMode(screenSize_X,screenSize_Y),       // size of the client area we want
        "Display an Image"                              // The text to appear on the window title
        );

    // load our image
    sf::Texture     texture;        // the texture which will contain our pixel data
    sf::Sprite      sprite;         // the sprite which will actually draw it
    loadImage("image.bmp",texture,sprite);

    // Set FPS so this draws at 60 FPS (note:  I didn't do this for the WinAPI version because it'd be too hard for such
    //  a small example)
    window.setFramerateLimit( 60 );
    
    bool program_running = true;        // true until the user wants to quit
    while(program_running)
    {
        // Do the event pump -- same idea as with Windows... look for events and process them
        sf::Event evt;
        while( window.pollEvent(evt) )      // while there are any events to process...
        {
            // process them. But we're only interested in the closed event
            if(evt.type == sf::Event::EventType::Closed)        // is this a close event?
                program_running = false;                        // indicate that we want the window to close
        }

        // now that events are processed... draw our image
        window.draw(sprite);        // just draw it to the back buffer
        window.display();           // and display it so the back buffer moves to the front
    }
}





So yeah.

My advice: Save yourself some headaches. Ditch the console, get a lib like SFML, and never look back.

If you're interested in making games... working in the console is a complete waste of time.
Topic archived. No new replies allowed.