0

Now I'm trying to display an image in view in the dialog in MFC.

The code as following.

void CTestview::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here

CRect rcWin;
GetWindowRect( &rcWin );
double ff;
ff=rcWin.Width();
rcWin.Height();

DoDisplayImage(); 
}

and

void CTestview::DoDisplayImage(void)
{

    CPoint pt;
    CRect rectClient;
    CDC * pDC;

    pDC = GetDC();
    GetClientRect(rectClient);


    int ii;
    ii=slider_val;
    (void) MagickCore::SetClientPath(fileposition);
    InitializeMagick(fileposition);
    Image m_Image;
    Image m_blurgray;
    int _imageHeight;

    try {
        //C:\work\mfc_test5\mfc_test5
        m_Image.read(fileposition);

    }
    catch(Exception)
    {
    return ;
    }


    char str_x[10];
    char str_y[10];
    if (pDC != NULL)
    {
        m_blurgray.gaussianBlur(20,2); //blur


        int   nImageY;
        int   nImageX;
        CSize sizeScaled;

        // Clear the background
        pDC->FillSolidRect(rectClient,pDC->GetBkColor());


        pt = rectClient.TopLeft();
        nImageX= m_Image.columns() ;
        //nImageY = m_Image.rows();
        CPoint aa;
        aa = rectClient.Size();

        // Extract the pixels from Magick++ image object
        PixelPacket *pPixels = m_Image.getPixels(0,0,m_Image.columns(),m_Image.rows());


        // Set up the Windows bitmap header
        BITMAPINFOHEADER bmi;
        bmi.biSize = sizeof(BITMAPINFOHEADER);
        bmi.biWidth =m_Image.columns();

        bmi.biHeight =  (-1)*m_Image.rows();
        bmi.biPlanes = 1;
        bmi.biBitCount = 32;
        bmi.biCompression = BI_RGB;
        bmi.biSizeImage = 0;
        bmi.biXPelsPerMeter = 0;
        bmi.biYPelsPerMeter = 0;
        bmi.biClrUsed = 0;
        bmi.biClrImportant = 0;

        // Blast it to the device context

        SetStretchBltMode(pDC->m_hDC,COLORONCOLOR);

        StretchDIBits(pDC->m_hDC,
            0,
            0,
            m_Image.columns(),
            m_Image.rows(),
            0,
            0,
            m_Image.columns(),
            m_Image.rows(),
            pPixels,
            (BITMAPINFO *)&bmi,
            DIB_RGB_COLORS,
            SRCCOPY);
        //UpdateData(FALSE);
    }
}

The problem is that display image have so much delay when I display an image into view. I don't know exactly what should I do for solving this problem.

update 1

I have update the code as following.

#pragma once
#include <Magick++.h>


// CTestview view

class CTestview : public CScrollView
{
    DECLARE_DYNCREATE(CTestview)

protected:
    CTestview();           // protected constructor used by dynamic creation
    virtual ~CTestview();

public:
#ifdef _DEBUG
    virtual void AssertValid() const;
#ifndef _WIN32_WCE
    virtual void Dump(CDumpContext& dc) const;
#endif
#endif

protected:
    virtual void OnDraw(CDC* pDC);      // overridden to draw this view
    virtual void OnInitialUpdate();     // first time after construct

    DECLARE_MESSAGE_MAP()
public:
    void DoDisplayImage(void);
    Image m_image


};

When I compile above code then I've got some error as following.

------ Build started: Project: mfc_test5, Configuration: Release Win32 ------
Build started 
PrepareForBuild:
  Creating directory "C:\work\mfc_test5\mfc_test5\Release\".
InitializeBuildStatus:
  Creating "Release\mfc_test5.unsuccessfulbuild" because "AlwaysCreate" was specified.
ClCompile:
  stdafx.cpp
  mfc_test5.cpp
c:\program files\imagemagick-6.8.6-q8\include\magick/pixel-accessor.h(160): warning C4244: '=' : conversion from 'double' to 'MagickCore::MagickRealType', possible loss of data
c:\work\mfc_test5\mfc_test5\mfc_test5\Testview.h(33): error C2143: syntax error : missing ';' before '}'
  mfc_test5Dlg.cpp
c:\program files\imagemagick-6.8.6-q8\include\magick/pixel-accessor.h(160): warning C4244: '=' : conversion from 'double' to 'MagickCore::MagickRealType', possible loss of data
c:\work\mfc_test5\mfc_test5\mfc_test5\Testview.h(33): error C2143: syntax error : missing ';' before '}'
C:\Program Files\Intel\plsuite\include\ipl.h(778): warning C4819: The file contains a character that cannot be represented in the current code page (949). Save the file in Unicode format to prevent data loss
C:\Program Files\Intel\plsuite\examples\Tutorial.IPL\IPLROOMS\COOKROOM\macros.inc(21): warning C4005: '_ASSERTE' : macro redefinition
          C:\Program Files\Microsoft Visual Studio 10.0\VC\include\crtdbg.h(213) : see previous definition of '_ASSERTE'

Build FAILED.

Time Elapsed 00:00:37.30
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I have found some reference code as following.as you can see, the following code use Image m_image.

How could it use like that?

// NtMagickView.h : interface of the CNtMagickView class
//
/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_NTMAGICKVIEW_H__8A45000C_6176_11D4_AC4F_400070168026__INCLUDED_)
#define AFX_NTMAGICKVIEW_H__8A45000C_6176_11D4_AC4F_400070168026__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define NTMAGICK_DEFEXT                "*.JPG;*.JPEG"
#define NTMAGICK_ALL                   "All Files (*.*)|*.*|"
#define NTMAGICK_BMP                   "Bitmaps (*.BMP;*.RLE)|*.BMP;*.RLE|"
#define NTMAGICK_GIF                   "GIF (*.GIF)|*.GIF|"
#define NTMAGICK_TIF                   "TIF (*.TIF;*.TIFF)|*.TIF;*.TIFF|"
#define NTMAGICK_JPEG                  "JPEG (*.JPG;*.JPEG)|*.JPG;*.JPEG|"
#define NTMAGICK_ICON                  "Icons (*.ICO)|*.ICO|"

class CNtMagickView : public CView
{
protected: // create from serialization only
        CNtMagickView();
        DECLARE_DYNCREATE(CNtMagickView)

// Attributes
public:
        CString       m_szFile;
        Image       * m_pImage;
        CNtMagickDoc* GetDocument();
        void          DoDisplayError(CString szFunction, CString szCause);
        void          DoDisplayImage();
        BOOL          DoReadImage();
        CSize         Scale(CSize sizeSrc, CSize sizeTgt);
        float         ScaleFactor(BOOL bAllowZoom, CSize sizeSrc, CSize sizeTgt);
        void          UpdateUI(CCmdUI* pCmdUI);

// Operations
public:

// Overrides
        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CNtMagickView)
        public:
        virtual void OnDraw(CDC* pDC);  // overridden to draw this view
        virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
        protected:
        //}}AFX_VIRTUAL

// Implementation
public:
        virtual ~CNtMagickView();
#ifdef _DEBUG
        virtual void AssertValid() const;
        virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
        //{{AFX_MSG(CNtMagickView)
        afx_msg void OnFileOpen();
        afx_msg void OnImageFlipHorizontal();
        afx_msg void OnUpdateImageFlipHorizontal(CCmdUI* pCmdUI);
        afx_msg void OnImageFlipVertical();
        afx_msg void OnUpdateImageFlipVertical(CCmdUI* pCmdUI);
        afx_msg void OnImageRotate180();
        afx_msg void OnUpdateImageRotate180(CCmdUI* pCmdUI);
        afx_msg void OnImageRotate90();
        afx_msg void OnUpdateImageRotate90(CCmdUI* pCmdUI);
        afx_msg void OnImageRotate90ccw();
        afx_msg void OnUpdateImageRotate90ccw(CCmdUI* pCmdUI);
    afx_msg void OnFileClear();
    afx_msg void OnUpdateFileClear(CCmdUI* pCmdUI);
    //}}AFX_MSG
        DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in NtMagickView.cpp
inline CNtMagickDoc* CNtMagickView::GetDocument()
   { return (CNtMagickDoc*)m_pDocument; }
#endif

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

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_NTMAGICKVIEW_H__8A45000C_6176_11D4_AC4F_400070168026__INCLUDED_)

Update 2

I have edited like as following but it is not called ever. is this right? when do it call this function?

void CTestview::OnInitialUpdate()
{
    CScrollView::OnInitialUpdate();

    CSize sizeTotal;
    // TODO: calculate the total size of this view
    sizeTotal.cx = sizeTotal.cy = 100;
    SetScrollSizes(MM_TEXT, sizeTotal);

    m_pimage.read(fileposition);
}
cabot
  • 73
  • 1
  • 7
  • Have you tried instrumenting your code with timers to see what is taking all the time? How big is your file? How long does it take to update? Can you do ImageMagick initialisation just once at the start of your program rather than before every drawing refresh? Is that a 20 pixel Gaussian blur in there - that will definitely be slow - try removing it temporarily. – Mark Setchell Nov 25 '15 at 14:51
  • @MarkSetchell How about that approach which is a display method in OnDraw()? is there any point of what should I have to change? – cabot Nov 25 '15 at 15:03
  • Small point but what is ff for and why is it double? CRect::Width () returns int. – Colin Nov 25 '15 at 15:04
  • @Colin Thanks let me know that, I'll try fix. But I think it does not any affect to display delay image. right? – cabot Nov 25 '15 at 15:08
  • @cabot Agreed, but pay attention to the compiler warnings you must be getting, they could help. – Colin Nov 25 '15 at 15:09
  • 1
    Why do you read image file from disk each time `OnDraw` is called? – Andrew Komiagin Nov 25 '15 at 16:07
  • Also I believe that `getPixels()` takes a while and there is no need to do this every time OnDraw is called. – Andrew Komiagin Nov 25 '15 at 16:17
  • @Andrew Komiagin : That is the only one which is image file read part. Should I have to move someware? I have no idea what put that part in somewhere. Please let me know your advice. If you don't mind, would you please give me how to fix them? You can see alsomy previous code at here.http://stackoverflow.com/questions/33653087/how-to-move-a-control-while-resizing-dialog-size-in-mfc/33663944?noredirect=1#comment55221468_33663944 – cabot Nov 25 '15 at 16:20
  • `Image m_Image;` should be defined as class member. You should move `read` call to `OnInitialUpdate()` of your view class. Also initialization stuff like `InitializeMagick(fileposition);` should move to OnInitInstance() of your app class. – Andrew Komiagin Nov 25 '15 at 16:29
  • Do you need `GaussianBlur()` - there is an optimised `Blur()` which may be hundreds of times faster. – Mark Setchell Nov 25 '15 at 16:39
  • @Andrew Komiagin : I can't understand why should m_image to be class member? How do I use m_image of class member? – cabot Nov 25 '15 at 16:51
  • The same way you are using it now. Just move the definition to a header file. I've noticed your local instances have **m_** prefix which means **class member** in Hungarian notation commonly used in MFC. So originally it was properly defined as class member. – Andrew Komiagin Nov 25 '15 at 16:56
  • @Andrew Komiagin: I've got an error when I just 'Image m_image' move to header .h after compile. Class 'Image' not found. I can't understand it. – cabot Nov 26 '15 at 06:38
  • You should also move corresponding `#include` where it is defined to the header. You have to learn C and C++ if you ask such questions. – Andrew Komiagin Nov 26 '15 at 06:53
  • @Andrew Komiagin : I already included #include into the header with 'Image m_image'. But you can see the result fail. – cabot Nov 26 '15 at 12:55
  • I've success make a class member. But I have some question what does it benefit like using this( declare class member ) instead of using local member variable? – cabot Nov 26 '15 at 13:46

1 Answers1

0

You should not draw directly on the TestView's DC, but instead create a compatible memory DC, do all the drawing on there, then copy the contents of the memory DC to the view's DC. Because it is way faster!

To do it, you can change the functions to call from OnDraw to receive a parameter that is the memory DC, and forbid yourself to do GetDC() everywhere except on creating the memory DC and copying back its contents to the view DC.

Your OnDraw should look like

void CTestview::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
// TODO: add draw code here

CDC draw_dc;
CBitmap draw_bitmap;
CBitmap* old_bitmap;

CRect draw_area;
pDC->GetClipBox(draw_area);

draw_dc.CreateCompatibleDC(pDC);
draw_bitmap.CreateCompatibleBitmap(pDC, draw_area.Width(), draw_area.Height());
old_bitmap = (CBitmap*)draw_dc.SelectObject(&draw_bitmap);

OnPrepareDC(&draw_dc, NULL);

pDC->LPtoDP(draw_area);
draw_dc.OffsetViewportOrg(-draw_area.left, -draw_area.top);
pDC->DPtoLP(draw_area);
draw_dc.IntersectClipRect(draw_area);

DoDisplayImage(&draw_dc);

pDC->BitBlt(draw_area.left, draw_area.top, draw_area.Width(), draw_area.Height(), &draw_dc, 0, 0, SRCCOPY);

draw_dc.SelectObject(old_bitmap);
DeleteObject(draw_bitmap);
DeleteDC(draw_dc);  
}

You may have noticed that there is some clipping code; it makes drawing faster because it will not draw on places where it doesn't need to do it. The most important parts are the draw_dc.CreateCompatibleDC(pDC); which creates the memory DC; and the pDC->BitBlt( ... , SRCCOPY); which copies the contents from memory to the view.

Side note: I removed the lines you had above because they seemed useless to me.

Now your DoDisplayImage function should be:

void CTestview::DoDisplayImage(CDC* pDC)
{
    CPoint pt;
    CRect rectClient;

    GetClientRect(rectClient);


    int ii;
    ii=slider_val;
    (void) MagickCore::SetClientPath(fileposition);
    InitializeMagick(fileposition);
    Image m_Image;
    Image m_blurgray;
    int _imageHeight;

    try {
        //C:\work\mfc_test5\mfc_test5
        m_Image.read(fileposition);

    }
    catch(Exception)
    {
    return ;
    }


    char str_x[10];
    char str_y[10];
    if (pDC != NULL)
    {
        m_blurgray.gaussianBlur(20,2); //blur


        int   nImageY;
        int   nImageX;
        CSize sizeScaled;

        // Clear the background
        pDC->FillSolidRect(rectClient,pDC->GetBkColor());


        pt = rectClient.TopLeft();
        nImageX= m_Image.columns() ;
        //nImageY = m_Image.rows();
        CPoint aa;
        aa = rectClient.Size();

        // Extract the pixels from Magick++ image object
        PixelPacket *pPixels = m_Image.getPixels(0,0,m_Image.columns(),m_Image.rows());


        // Set up the Windows bitmap header
        BITMAPINFOHEADER bmi;
        bmi.biSize = sizeof(BITMAPINFOHEADER);
        bmi.biWidth =m_Image.columns();

        bmi.biHeight =  (-1)*m_Image.rows();
        bmi.biPlanes = 1;
        bmi.biBitCount = 32;
        bmi.biCompression = BI_RGB;
        bmi.biSizeImage = 0;
        bmi.biXPelsPerMeter = 0;
        bmi.biYPelsPerMeter = 0;
        bmi.biClrUsed = 0;
        bmi.biClrImportant = 0;

        // Blast it to the device context

        SetStretchBltMode(pDC->m_hDC,COLORONCOLOR);

        StretchDIBits(pDC->m_hDC,
            0,
            0,
            m_Image.columns(),
            m_Image.rows(),
            0,
            0,
            m_Image.columns(),
            m_Image.rows(),
            pPixels,
            (BITMAPINFO *)&bmi,
            DIB_RGB_COLORS,
            SRCCOPY);
        //UpdateData(FALSE);
    }
}

Side note: You seem to also have useless code here, namely the parts with aa and ii variables.

sergiol
  • 4,122
  • 4
  • 47
  • 81