Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Lightweight Image Viewer for Windows Mobile (WinCE)

0.00/5 (No votes)
23 Nov 2007 1  
Demonstrates how to show any size BMP or JPEG image on a Pocket PC screen and scroll it up to its limits
Screenshot - wmimgvwr_01.jpg

Introduction

This article intends to explain the principles of coding an image viewer for Pocket PCs. The sample application is simple. There are no advanced features like zoom in/out or image rotate. In fact, there are only 3 main points that I want to explain in the sample:

  1. How to toggle a window to full screen mode.
  2. How to load a JPEG image and draw it on a window.
  3. How to scroll the image when it is bigger than the screen area (by using a stylus pen).

A Quick View of the Image Viewer Sample

wmimgvwr is a C++/MFC application coded using Visual Studio 2005. You can build the final executable either to PPC 2003 or to Windows Mobile 5. There are two forms of opening an image with vmimgvwr:

  1. Starting it with no arguments, an Open File Dialog (CFileDialog) is going to be shown (Figure 1). The main problem with CFileDialog is that it allows access only to files and folders in the \My Documents folder.
  2. Starting it by passing a full image path, for instance, an application can start wmimgvwr by calling the CreateProcess API function:
PROCESS_INFORMATION procInfo;

CreateProcess( L"\\Apps\\wmimgvwr.exe",
               L"\\Images\\fig1.bmp",
               NULL,
               NULL,
               FALSE,
               NULL,
               NULL,
               NULL,
               NULL,
               &procInfo );
Screenshot - wmimgvwr_02.jpg

Figure 1

At the upper-left corner of the window, there is a close button. In fact, it is not a button but a picture control (Figure 2). While you are scrolling the image, that button is not visible. Thus, you can see all image details (Figure 3).

Screenshot - wmimgvwr_03.jpg

Figure 2

Screenshot - wmimgvwr_04.jpg

Figure 3

Understanding the Source Code

Now it is time to explain the main points of the source code.

1. How to Toggle the Window to Full Screen Mode

Pocket PCs have low resolution screens (320x240 or 240x240). So it is good to use all that resolution to display an image, right? wmimgvwr is a dialog application. It is a dialog with no title bar or system menu. However, that is not enough. We need some coding to toggle the dialog to full screen mode. Take a look at wmimgvwrDlg.cpp (line 91):

// *** FULL SCREEN - BEGIN
   SHINITDLGINFO shidi;
   (void) ::ZeroMemory(&shidi, sizeof(shidi));
   shidi.dwMask  = SHIDIM_FLAGS;
   shidi.dwFlags = SHIDIF_FULLSCREENNOMENUBAR;
   shidi.hDlg    = this->m_hWnd;

   ::SHInitDialog(&shidi);

   this->uf_full_screen(); 
   // *** FULL SCREEN - END

SHInitDialog is used to set the dialog to full screen using SHIDIF_FULLSCREENNOMENUBAR, which removes the command bar from the dialog. Surprisingly, the result is not a full-screen window, but it is still necessary. Member that function uf_full_screen() got the rest of the necessary code (wmimgvwrDlg.h, line 60):

void uf_full_screen(BOOL _bMove = TRUE)
   {
      HWND hBar = ::SHFindMenuBar(this->m_hWnd);
      ::CommandBar_Show( hBar, FALSE );

      this->SetForegroundWindow();
      ::SHFullScreen( this->m_hWnd, 
          SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON );

      RECT cliRect;
      this->GetClientRect(&cliRect);

      if ( _bMove )
      {
         cliRect.top -= vg_wintask_h;
         cliRect.bottom += vg_wintask_h;
         this->MoveWindow(&cliRect);
      }
   }

The first two lines of the function contain the code to hide the command bar (SHFindMenuBar and CommandBar_Show). Next, SHFullScreen gives privileges to the dialog window to cover the task bar and SIP button. That is the best way I found to describe what SHFullScreen really does, as a call to it does not produce a full screen window. Besides, you must call SetForegroundWindow before calling it.

Finally, you must resize the window to cover all the screen. I mean that the window must cover the task bar area, as well. So, what is the height of the task bar? Usually 26 pixels, but we can never be sure. Take a look at the variable vg_wintask_h (wmimgvwrDlg.h, line 73). Its value is the task bar height. wmimgvwr.cpp, line 52 shows how it gets that value.

2. How to Load a JPEG Image File and Draw It on a Window

Bitmaps are drawn on a window's client area. So, all you need to do is load the bitmap file, get the handle and use the appropriated functions to draw it. MFC gives us the CBitmap and CDC classes. Both are enough to load and display a bitmap file, but how about JPEG files?

You might think that is a problem because there is no CJPEG class to load a JPEG file and convert it to a bitmap. In fact, even basic functions like LoadImage only accept bitmaps, icons or cursor files to load. Don't worry; you will not have to search the Internet looking for a JPEG library for Windows CE. Take a look at the uf_load_bitmap member function defined in wmimgvwrDlg.cpp (line 183). There is such a cool function called SHLoadImageFile that allows an application to load several types of images and convert all of them to bitmaps! Then the application can attach the CBitmap class to the bitmap handle returned by SHLoadImageFile and easily deal with it. Notice that it can load GIF and PNG files.

3. How to Scroll the Image When It is Bigger than the Screen Area (by Using a Stylus Pen)

Drawing a bitmap on a window's client area is a simple matter of calling the BitBlt function and passing the correct arguments. How to control those argument values might be a problem. Member function OnPaint defined at wmimgvwrDlg.cpp (line 125) is called every time a window needs to be redrawn. The following code is always executed when OnPaint is called:

dc.BitBlt( this->m_img_pos.dc_x, 
            this->m_img_pos.dc_y, 
            this->m_img_pos.dc_crop_cx, 
            this->m_img_pos.dc_crop_cy, 
            &this->m_dcMem, 
            this->m_img_pos.bmp_x, 
            this->m_img_pos.bmp_y, 
            SRCCOPY );

Member variable m_img_pos is a structure defined at globals.h. Some fields are initialized in uf_load_bitmap and others in the uf_calc_bmp_pos member function (wmimgvwrDlg.cpp, line 148). uf_calc_bmp_pos does the following: if the image is smaller than the window's client area, then the image is centered in the window. Otherwise, the central part of the image is drawn on the window's client area.

Image scrolling is controlled in the PreTranslateMessage member function (wmimgvwrDlg.cpp, line 227). Notice how the visible state of the close button is controlled (lines 239 and 301). The WM_MOUSEMOVE message is handled to deal with scrolling and scroll only happens if the image does not fit in the window. Two Boolean fields in the m_img_pos structure control image scrolling: bmp_scroll_x and bmp_scroll_y.

The bmp_x and bmp_y fields are the fields that have their values changed depending on pen action. Finally, if a scroll really happens, a call to Invalidate is made to force the window's client area to be redrawn (line 295).

Enjoy. I hope this helps.

History

23 November, 2007 -- First version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here