[Insight-users] Image reader problem

Charles Knox knoxcharles at qwest.net
Fri May 9 18:07:02 EDT 2008


Hi Bill and Luis,

I've written a short test routine, DICOMReaderTest, that duplicates the 
behavior I described previously.  It is a Windows single-document app 
written for Visual Studio 2008.  See the listing below. 

I had also thought my larger app was stepping on memory somewhere, 
trashing the ITK code.  However, this shorter test app also misbehaves 
in exactly the same way - crashing in an ITK destructor on return from 
the ReadDICOMImage() routine.  Briefly, the program works as follows:  
An ID_FILE_OPEN command is handled by CDICOMReaderTest::OnFileNew, which 
opens a CFileDialog to request a file name.  
CDICOMReaderTest::ReadDICOMImage is called to retrieve the file.  An 
error is generated at reader->Update and the program then crashes on the 
return from the 'catch' handler.

Regards,
Charles Knox

Bill Lorensen wrote:
> Also, it is possible that your code has a problem elsewhere that has
> only surfaced after switching to the new compiler. You could be
> trashing memory somewhere.
>
> Can you post a small test program that crashes? We could try to run it
> through a memory checker like valgrind.
>
> Bill
>   
------------------------------------------------------------------------------------------------------------------
// DICOMReaderTest.h : main header file for the DICOMReaderTest application
//
#pragma once
#ifndef __AFXWIN_H__
    #error "include 'stdafx.h' before including this file for PCH"
#endif
#include "resource.h"       // main symbols
// CDICOMReaderTestApp:
// See DICOMReaderTest.cpp for the implementation of this class
//
class CDICOMReaderTestApp : public CWinApp
{
public:
    CDICOMReaderTestApp();
// Overrides
public:
    virtual BOOL InitInstance();
// Implementation
    afx_msg void OnAppAbout();
    DECLARE_MESSAGE_MAP()
};
extern CDICOMReaderTestApp theApp;
------------------------------------------------------------------------------------------------------------------
// DICOMReaderTest.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "DICOMReaderTest.h"
#include "MainFrm.h"
#include <locale>

#include "DICOMReaderTestDoc.h"
#include "DICOMReaderTestView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CDICOMReaderTestApp

BEGIN_MESSAGE_MAP(CDICOMReaderTestApp, CWinApp)
    ON_COMMAND(ID_APP_ABOUT, &CDICOMReaderTestApp::OnAppAbout)
    // Standard file based document commands
    ON_COMMAND(ID_FILE_NEW, &CWinApp::OnFileNew)
    ON_COMMAND(ID_FILE_OPEN, &CWinApp::OnFileOpen)
    // Standard print setup command
    ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()

// CDICOMReaderTestApp construction

CDICOMReaderTestApp::CDICOMReaderTestApp()
{
    // TODO: add construction code here,
    // Place all significant initialization in InitInstance
}

// The one and only CDICOMReaderTestApp object
CDICOMReaderTestApp theApp;
// CDICOMReaderTestApp initialization

BOOL CDICOMReaderTestApp::InitInstance()
{
    // InitCommonControlsEx() is required on Windows XP if an application
    // manifest specifies use of ComCtl32.dll version 6 or later to enable
    // visual styles.  Otherwise, any window creation will fail.
    INITCOMMONCONTROLSEX InitCtrls;
    InitCtrls.dwSize = sizeof(InitCtrls);
    // Set this to include all the common control classes you want to use
    // in your application.
    InitCtrls.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&InitCtrls);

    setlocale(LC_ALL, "English");

    CWinApp::InitInstance();
    // Initialize OLE libraries
    if (!AfxOleInit())
    {
        AfxMessageBox(IDP_OLE_INIT_FAILED);
        return FALSE;
    }
    AfxEnableControlContainer();
    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need
    // Change the registry key under which our settings are stored
    // TODO: You should modify this string to be something appropriate
    // such as the name of your company or organization
    SetRegistryKey(_T("Local AppWizard-Generated Applications"));
    LoadStdProfileSettings(4);  // Load standard INI file options 
(including MRU)
    // Register the application's document templates.  Document templates
    //  serve as the connection between documents, frame windows and views
    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate(
        IDR_MAINFRAME,
        RUNTIME_CLASS(CDICOMReaderTestDoc),
        RUNTIME_CLASS(CMainFrame),       // main SDI frame window
        RUNTIME_CLASS(CDICOMReaderTestView));
    if (!pDocTemplate)
        return FALSE;
    AddDocTemplate(pDocTemplate);

    // Parse command line for standard shell commands, DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);

    // Dispatch commands specified on the command line.  Will return 
FALSE if
    // app was launched with /RegServer, /Register, /Unregserver or 
/Unregister.
    if (!ProcessShellCommand(cmdInfo))
        return FALSE;

    // The one and only window has been initialized, so show and update it
    m_pMainWnd->ShowWindow(SW_SHOW);
    m_pMainWnd->UpdateWindow();
    // call DragAcceptFiles only if there's a suffix
    //  In an SDI app, this should occur after ProcessShellCommand
    return TRUE;
}

// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
    CAboutDlg();

// Dialog Data
    enum { IDD = IDD_ABOUTBOX };
protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
// App command to run the dialog
void CDICOMReaderTestApp::OnAppAbout()
{
    CAboutDlg aboutDlg;
    aboutDlg.DoModal();
}

// CDICOMReaderTestApp message handlers
------------------------------------------------------------------------------------------------------------------
// DICOMReaderTestDoc.h : interface of the CDICOMReaderTestDoc class
//
using namespace std;
#pragma once
class CDICOMReaderTestDoc : public CDocument
{
protected: // create from serialization only
    CDICOMReaderTestDoc();
    DECLARE_DYNCREATE(CDICOMReaderTestDoc)

// Attributes
public:
    CString        m_path;      // Complete pathname of the DICOM file read.
    BYTE *        m_image;   // DICOM data
    CSize        m_imageSize;   // x,y size of image

// Operations
public:
    BOOL        ReadDICOMImage(const LPCTSTR path);

// Overrides
public:
    virtual BOOL OnNewDocument();
    virtual void Serialize(CArchive& ar);

// Implementation
public:
    virtual ~CDICOMReaderTestDoc();
#ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
    DECLARE_MESSAGE_MAP()
public:
    afx_msg void OnFileOpen();
};

------------------------------------------------------------------------------------------------------------------
// DICOMReaderTestDoc.cpp : implementation of the CDICOMReaderTestDoc class
//
#include "stdafx.h"
#include "itkGDCMImageIO.h"
#include "itkImageRegionIterator.h"
#include "itkImageFileReader.h"
#include "DICOMReaderTest.h"
#include "DICOMReaderTestDoc.h"
//#include <string>

//using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CDICOMReaderTestDoc
IMPLEMENT_DYNCREATE(CDICOMReaderTestDoc, CDocument)

BEGIN_MESSAGE_MAP(CDICOMReaderTestDoc, CDocument)
    ON_COMMAND(ID_FILE_OPEN, &CDICOMReaderTestDoc::OnFileOpen)
END_MESSAGE_MAP()

// CDICOMReaderTestDoc construction/destruction

CDICOMReaderTestDoc::CDICOMReaderTestDoc()
{
    m_image = NULL;
}

CDICOMReaderTestDoc::~CDICOMReaderTestDoc()
{
    delete [] m_image;
}

BOOL CDICOMReaderTestDoc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;

    // TODO: add reinitialization code here
    // (SDI documents will reuse this document)
    return TRUE;
}

// CDICOMReaderTestDoc serialization

void CDICOMReaderTestDoc::Serialize(CArchive& ar)
{
    if (ar.IsStoring())
    {
        // TODO: add storing code here
    }
    else
    {
        // TODO: add loading code here
    }
}

// CDICOMReaderTestDoc diagnostics

#ifdef _DEBUG
void CDICOMReaderTestDoc::AssertValid() const
{
    CDocument::AssertValid();
}

void CDICOMReaderTestDoc::Dump(CDumpContext& dc) const
{
    CDocument::Dump(dc);
}
#endif //_DEBUG

// CDICOMReaderTestDoc commands

void CDICOMReaderTestDoc::OnFileOpen()
// Gets a file name from the user
{
    CFileDialog dlg(TRUE, 0, _T("*.*"));

    if (dlg.DoModal() != IDOK)
        return;
    CString folder        = dlg.GetFolderPath() + _T("\\");
    CString filename    = dlg.GetFileName();
    m_path        = folder + filename;

// Call the read routine
    if (ReadDICOMImage(m_path))
       // Signal the view to draw the image
        UpdateAllViews(NULL);
}


BOOL CDICOMReaderTestDoc::ReadDICOMImage( const LPCTSTR path)
{
    std::string spath((char *)path);
    // First check for a DICOM file.
    itk::GDCMImageIO::Pointer gdcmIO = itk::GDCMImageIO::New();

    if (!gdcmIO->CanReadFile(spath.c_str()))
        return FALSE;
    delete [] m_image;
    m_image = NULL;

    typedef signed short                        PixelType;
    // Set dimensions to 3 to have reader return z-value
    const    UINT                                Dimension = 3;
    typedef itk::Image< PixelType, Dimension >    ImageType;
    typedef itk::ImageFileReader< ImageType >    ReaderType;

    ReaderType::Pointer reader = ReaderType::New();

    reader->SetFileName(spath.c_str() );
    reader->SetImageIO( gdcmIO );

    // Return prematurely to invoke 'reader' destructor
    //return FALSE;

    try {
        reader->Update();
    } catch (std::exception &err) {
        CString msg(err.what());
        AfxMessageBox(msg);
        return FALSE;               // Crashes on return
    }

    ImageType::Pointer image = reader->GetOutput();

    // Image size
    ImageType::SizeType size = image->GetLargestPossibleRegion().GetSize();
    m_imageSize.cx    = size[0];
    m_imageSize.cy    = size[1];

    long bytesPerPixel    = sizeof(PixelType);
    long nPixels = m_imageSize.cx * m_imageSize.cy;
    long nBytes = nPixels * bytesPerPixel;

    // Transfer image data into buffer
    typedef itk::ImageRegionIterator< ImageType > IteratorType;
    IteratorType iter( image, image->GetLargestPossibleRegion() );

    PixelType *data = new PixelType[nPixels];
    PixelType *row  = new PixelType[m_imageSize.cx];
    PixelType *pB   = data + nPixels - m_imageSize.cx;

    iter.GoToBegin();

    // get data and mirror y
    for (int j = 0; j < m_imageSize.cy; j++) {
        for (int i = 0; i < m_imageSize.cx; i++, ++iter)
            *(row + i) = iter.Get();
        memcpy((void *)pB, (void *)row, m_imageSize.cx * sizeof(PixelType));
        pB -= m_imageSize.cx;
    }
    delete [] row;
    m_image = new BYTE[nPixels];

    if (sizeof(PixelType) == 1) {
        // DICOM data are going to be 2-bpp
        // but just in case...
        memcpy( m_image, data, nPixels);
       delete [] data;
        return TRUE;
    }

    // Convert (possibly) signed pixels to unsigned, rescale
    // and save image in member variable m_image.
    int i;
    PixelType min, max, *pd = data, maxgray = ~0;

    for ( i = 0; i < nPixels; pd++, i++) {
        if (*pd < min)
            min = *pd;
        if (*pd > max)
            max = *pd;
    }
    long pixel, offset = min, range = max - min;

    for ( i = 0, pd = data; i < nPixels; i++) {
        pixel = (((long )*pd++ - offset) * (long)maxgray)/range;
        m_image[i] = (BYTE)(pixel >> 8);
    }
    delete [] data;

    return TRUE;
}
------------------------------------------------------------------------------------------------------------------
// DICOMReaderTestView.h : interface of the CDICOMReaderTestView class
//
#include "ImageDC.h"
#pragma once

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

// Attributes
public:
    CDICOMReaderTestDoc* GetDocument() const;

// Operations
public:
    CImageDC    m_imageDC;

// Overrides
public:
    virtual void OnDraw(CDC* pDC);  // overridden to draw this view
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
    virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
    virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
    virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

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

protected:
// Generated message map functions
protected:
    DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in DICOMReaderTestView.cpp
inline CDICOMReaderTestDoc* CDICOMReaderTestView::GetDocument() const
   { return reinterpret_cast<CDICOMReaderTestDoc*>(m_pDocument); }
#endif

------------------------------------------------------------------------------------------------------------------
// DICOMReaderTestView.cpp : implementation of the CDICOMReaderTestView 
class
//
#include "stdafx.h"
#include "DICOMReaderTest.h"

#include "DICOMReaderTestDoc.h"
#include "DICOMReaderTestView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CDICOMReaderTestView

IMPLEMENT_DYNCREATE(CDICOMReaderTestView, CView)

BEGIN_MESSAGE_MAP(CDICOMReaderTestView, CView)
    // Standard printing commands
    ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
END_MESSAGE_MAP()

// CDICOMReaderTestView construction/destruction

CDICOMReaderTestView::CDICOMReaderTestView()
{
}

CDICOMReaderTestView::~CDICOMReaderTestView()
{
}

BOOL CDICOMReaderTestView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    return CView::PreCreateWindow(cs);
}

// CDICOMReaderTestView drawing

void CDICOMReaderTestView::OnDraw(CDC* pDC)
// Draws the image if read
{
    CDICOMReaderTestDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    if (pDoc->m_image == 0)
        return;
 
    // Create source device context with bitmap
    m_imageDC.Delete();
    // Load image data into source device context bitmap
    m_imageDC.Create(pDC, pDoc->m_image, pDoc->m_imageSize, 2.2);
    m_imageDC.LoadBmp();
    pDC->BitBlt(0, 0, pDoc->m_imageSize.cx, pDoc->m_imageSize.cy,
        &m_imageDC, 0, 0, SRCCOPY);
}


// CDICOMReaderTestView printing

BOOL CDICOMReaderTestView::OnPreparePrinting(CPrintInfo* pInfo)
{
    // default preparation
    return DoPreparePrinting(pInfo);
}

void CDICOMReaderTestView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* 
/*pInfo*/)
{
    // TODO: add extra initialization before printing
}

void CDICOMReaderTestView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* 
/*pInfo*/)
{
    // TODO: add cleanup after printing
}

// CDICOMReaderTestView diagnostics

#ifdef _DEBUG
void CDICOMReaderTestView::AssertValid() const
{
    CView::AssertValid();
}

void CDICOMReaderTestView::Dump(CDumpContext& dc) const
{
    CView::Dump(dc);
}

CDICOMReaderTestDoc* CDICOMReaderTestView::GetDocument() const // 
non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CDICOMReaderTestDoc)));
    return (CDICOMReaderTestDoc*)m_pDocument;
}
#endif //_DEBUG


// CDICOMReaderTestView message handlers
------------------------------------------------------------------------------------------------------------------
// GrayPalette.h

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// GrayPalette.h : header file
//
#define NGRAYS_8U 256
/////////////////////////////////////////////////////////////////////////////
// CGrayPalette window

class CGrayPalette : public CWnd
{
// Construction
public:
    CGrayPalette();

// Attributes
public:

// Operations
public:
    // Constructs a linear ramp gray value palette with selectable gamma.
    // Adds color red between 'lower' and 'upper' levels with selectable 
opacity.
    void    ThresholdPalette(int lower, int upper,
                    double opacity, double gamma, RGBQUAD 
palette[NGRAYS_8U]);

    void    RampPalette(int lower, int upper, double gamma, RGBQUAD 
palette[NGRAYS_8U]);

    void    BinaryPalette(int lower, int upper, RGBQUAD palette[NGRAYS_8U]);


// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CGrayPalette)
    //}}AFX_VIRTUAL

// Implementation
public:
    virtual ~CGrayPalette();

    // Generated message map functions
protected:
    //{{AFX_MSG(CGrayPalette)
        // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

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

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

------------------------------------------------------------------------------------------------------------------
// GrayPalette.cpp : implementation file
//

#include "stdafx.h"
#include "GrayPalette.h"
#include "math.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CGrayPalette

CGrayPalette::CGrayPalette()
{
}

CGrayPalette::~CGrayPalette()
{
}

BEGIN_MESSAGE_MAP(CGrayPalette, CWnd)
    //{{AFX_MSG_MAP(CGrayPalette)
        // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGrayPalette message handlers

void CGrayPalette::ThresholdPalette(int lower, int upper,
                    double opacity, double gamma, RGBQUAD 
palette[NGRAYS_8U])
/**
 *    Makes a gray level palette suitable for use with a DIB section image.

     If the 'lower' and 'upper' values are both zero, a gamma-corrected gray
    value linear ramp palette is returned.  In this case, 'opacity' is 
not used.

    If either 'lower' or 'upper' is nonzero, the color red is applied to
    the range of values 'lower' to 'upper'. 'opacity' of 1.0 gives a 
solid color,
    whereas, values between 0 and 1.0 give varying degrees of transparency.
    'gamma' is typically 1.0 to 2.2.

    Return values:  An array of NGRAYS_8U (256) RGBQUAD values
 */
{
    int i;
    double    val;
    UINT    lval;
    BYTE maxGray = ~0, red = maxGray;

    // Make a gamma corrected gray ramp
    for (i = 0; i != NGRAYS_8U; i++) {
        val = (double )maxGray * pow((double)i / (double )maxGray, 1 / 
gamma) + 0.5;
        lval = (UINT )val;
        palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = lval;
        palette[i].rgbReserved = 0xff;
    }
    if(lower == 0 && upper == 0)
        return;
    // If opaque, insert color red in LUT for showing thresholded values
    if (opacity >= 1) {
        for (i = lower; i <= upper; i++) {
            palette[i].rgbRed = red;
            palette[i].rgbReserved = maxGray;
            palette[i].rgbGreen = palette[i].rgbBlue = 0;
        }
    // otherwise, blend in the color.
    } else if (opacity == 0.5) {
        for (i = lower; i <= upper; i++) {
            palette[i].rgbGreen >>= 1;
            palette[i].rgbBlue >>= 1;
            palette[i].rgbRed >>= 1;
            palette[i].rgbRed += (red >> 1);
        }
    } else {
        double r, g, b;

        for (i = lower; i <= upper; i++) {
            r = (double )palette[i].rgbRed   * (1 - opacity) + (double 
)red * opacity;
            g = (double )palette[i].rgbGreen * (1 - opacity);
            b = (double )palette[i].rgbBlue  * (1 - opacity);
            palette[i].rgbRed   = (BYTE )r;
            palette[i].rgbGreen = (BYTE )g;
            palette[i].rgbBlue  = (BYTE )b;
        }
    }
}

void CGrayPalette::RampPalette(int lower, int upper,
                                    double gamma, RGBQUAD 
palette[NGRAYS_8U])
{
    BYTE maxGray = ~0;
    int i;

    ZeroMemory((void *)palette, lower * sizeof(RGBQUAD));
    for ( i = maxGray; i > upper; i--) {
        palette[i].rgbBlue = maxGray;
        palette[i].rgbGreen = maxGray;
        palette[i].rgbRed = maxGray;
        palette[i].rgbReserved = maxGray;
    }
    // Make a gamma corrected gray ramp between lower and upper
    double gVal, d = (double )(upper - lower);
    if (d == 0)
        d = 1;
    for (i = lower; i <= upper; i++) {
        gVal = ((double )maxGray * (double )(i - lower)) / d;
        gVal = (double )maxGray * pow(gVal / (double )maxGray, 1 / 
gamma) + 0.5;

        palette[i].rgbBlue = (BYTE )gVal;
        palette[i].rgbGreen = (BYTE )gVal;
        palette[i].rgbRed = (BYTE )gVal;
        palette[i].rgbReserved = maxGray;
    }
}

void CGrayPalette::BinaryPalette(int lower, int upper, RGBQUAD 
palette[NGRAYS_8U])
{
    BYTE maxGray = ~0;

    ZeroMemory((void *)palette, 256 * sizeof(RGBQUAD));
    for (int i = lower; i <= upper; i++) {
        palette[i].rgbBlue = maxGray;
        palette[i].rgbGreen = maxGray;
        palette[i].rgbRed = maxGray;
        palette[i].rgbReserved = maxGray;
    }
}
------------------------------------------------------------------------------------------------------------------
// ImageDC.h: interface for the CImageDC class.
//            It provides device context with bitmap to draw the image
//
//////////////////////////////////////////////////////////////////////

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//#include "ImageData.h"

class CImageDC : public CDC 
{
public:
    CImageDC();
    virtual ~CImageDC();

    // Attach pImage
    // Create DC, compatible with pDC
    // Create DIB section for pImage and select it into DC
    // the initial color table is a linear gray ramp
    void Create(CDC* pDC, BYTE* pImage, CSize size, double gamma);

    // Copy data from attached image to DIB section
    void        LoadBmp();

    bool        HaveBmp() { return m_pBits != NULL; }
    void        GetBmp(BYTE *pBits);

    // Sets the DIB section's color table
    void        SetColorTable(UINT startIndex, UINT numberColors, 
RGBQUAD *colors);
    void        Delete();

public:
    // Attributes

protected:
   BITMAPINFO* GetBmpInfo()
   {
       return (BITMAPINFO *)m_BmpInfoPalette;
   }
   BITMAPINFOHEADER* GetBmpInfoHeader()
   {
       return (BITMAPINFOHEADER *)m_BmpInfoPalette;
   }
   RGBQUAD* GetBmpPalette()
   {
       return GetBmpInfo()->bmiColors;
   }
   BOOL SetBmpInfo(void );
   void SetGrayPalette();

   double        m_gamma;    // Gamma correction value from Create()
   HBITMAP        m_hBmp;
   BYTE*        m_pImg;
   BYTE            m_BmpInfoPalette[sizeof(BITMAPINFO)+256*sizeof(RGBQUAD)];
   BYTE*        m_pBits;
   CSize        m_size;
   int            m_step;        // Number of bytes to step thru rows in 
the bitmap
};

------------------------------------------------------------------------------------------------------------------
// ImageDC.cpp: implementation of the CImageDC class.
//
// Creates an 8-bit DIB section of the supplied gray value
// image data.
//
// Use the Create() function to initialize the DIB section.
//
// Call LoadBmp() to load the actual image data into the bitmap.
// Image data are assumed to be 8-bits per pixel.
// The default palette will be set with a linear gray ramp.
//
// Use CDC::BitBlt or CDC::StretchBlt to display the bitmap
// on the device context.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ImageDC.h"
#include "GrayPalette.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CImageDC::CImageDC()
{
    m_pImg  = NULL;
    m_pBits = NULL;
    m_hBmp  = NULL;
    m_gamma = 2.2;
    memset(m_BmpInfoPalette, 0,
        sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD));
    SetGrayPalette();
}

CImageDC::~CImageDC()
{
   Delete();
}

void CImageDC::Create(CDC* pDC, BYTE* pImg, CSize size, double gamma)
// Creates a DC, compatible with pDC.  A DIB section for pImg
// of size 'size' is then created and selected into the DC.
// The initial color table of the DIB section is a linear gray ramp.
{
    ASSERT(pDC);
    ASSERT(pImg);

    m_pImg = NULL;
    m_hBmp = NULL;
    m_gamma = gamma;
    m_size = size;
    // m_step - width in pixels. pixels will be DWORDs and
    // width must be rounded up to the next DWORD sized pixel.
    m_step = ((m_size.cx + 3) >> 2) << 2;
    CreateCompatibleDC(pDC);
    if (!SetBmpInfo()) return;
    m_pImg = pImg;
    m_hBmp = ::CreateDIBSection( GetSafeHdc(), GetBmpInfo(),
        DIB_RGB_COLORS, (void **)(&m_pBits), NULL, 0);

    ASSERT(m_hBmp);

    SelectObject(m_hBmp);
}

void CImageDC::Delete()
// Call this function to delete the DIB section
// from the device context when no longer needed.
{
    if (m_hBmp == NULL)
        return;
    ::DeleteObject(m_hBmp);
    m_pImg = NULL;
    m_pBits = NULL;
    m_hBmp = NULL;
    DeleteDC();
}

void CImageDC::LoadBmp()
{
    if (m_pBits && m_pImg) {
        BYTE *q = m_pBits;    // Pointer to bitmap
        BYTE *p = m_pImg;    // and to source image

        for (int i = 0; i < m_size.cy; i++) {
            // Copy one line at a time
            CopyMemory(q, p, m_size.cx);
            q += m_step;
            p += m_size.cx;
        }
    }
}

void CImageDC::GetBmp(BYTE *pBits)
{
    if (m_pBits) {
        BYTE *q = m_pBits;    // Pointer to bitmap

        for (int i = 0; i < m_size.cy; i++) {
            // Copy one line at a time
            CopyMemory(pBits, q, m_size.cx);
            q += m_step;
            pBits += m_size.cx;
        }
    }
}

BOOL CImageDC::SetBmpInfo( void )
{
    BITMAPINFO* bmInfo = GetBmpInfo();
    BITMAPINFOHEADER* bi = GetBmpInfoHeader();
   
    bi->biSize = sizeof(BITMAPINFOHEADER);
    bi->biWidth = m_step;
    bi->biHeight = m_size.cy;
    bi->biPlanes = 1;
    bi->biCompression = BI_RGB;
    bi->biBitCount = 8;
    bi->biSizeImage = ((((bi->biWidth * bi->biBitCount) + 31) &
        ~31) >> 3) * bi->biHeight;
    bi->biXPelsPerMeter = 0;
    bi->biYPelsPerMeter = 0;
    bi->biClrUsed = 256;
    bi->biClrImportant = 0;
    SetGrayPalette();
    return TRUE;
}

void CImageDC::SetGrayPalette()
{
    CGrayPalette pal;
    RGBQUAD* bmPalette = GetBmpPalette() ;


    pal.RampPalette(0, NGRAYS_8U - 1, m_gamma, bmPalette);
}

void CImageDC::SetColorTable(UINT startIndex, UINT numberColors, RGBQUAD 
*colors)
// The color table in the DIB section has 256 entries.  Call this
// function to alter the current values.
{
    if (!m_hBmp)
        return;
#ifdef _DEBUG
    ASSERT (numberColors <= 256);
#endif
    SetDIBColorTable(GetSafeHdc(), startIndex, numberColors, colors);

}


------------------------------------------------------------------------------------------------------------------
// MainFrm.h : interface of the CMainFrame class
//

#pragma once

class CMainFrame : public CFrameWnd
{
protected: // create from serialization only
    CMainFrame();
    DECLARE_DYNCREATE(CMainFrame)

// Attributes
public:

// Operations
public:

// Overrides
public:
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

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

protected:  // control bar embedded members
    CStatusBar  m_wndStatusBar;
    CToolBar    m_wndToolBar;

// Generated message map functions
protected:
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    DECLARE_MESSAGE_MAP()
};
------------------------------------------------------------------------------------------------------------------
// MainFrm.cpp : implementation of the CMainFrame class
//

#include "stdafx.h"
#include "DICOMReaderTest.h"

#include "MainFrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    ON_WM_CREATE()
END_MESSAGE_MAP()

static UINT indicators[] =
{
    ID_SEPARATOR,           // status line indicator
    ID_INDICATOR_CAPS,
    ID_INDICATOR_NUM,
    ID_INDICATOR_SCRL,
};

// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
    // TODO: add member initialization code here
}

CMainFrame::~CMainFrame()
{
}


int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
   
    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE 
| CBRS_TOP
        | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
        !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
    {
        TRACE0("Failed to create toolbar\n");
        return -1;      // fail to create
    }

    if (!m_wndStatusBar.Create(this) ||
        !m_wndStatusBar.SetIndicators(indicators,
          sizeof(indicators)/sizeof(UINT)))
    {
        TRACE0("Failed to create status bar\n");
        return -1;      // fail to create
    }

    // TODO: Delete these three lines if you don't want the toolbar to 
be dockable
    m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
    EnableDocking(CBRS_ALIGN_ANY);
    DockControlBar(&m_wndToolBar);

    return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    return TRUE;
}


// CMainFrame diagnostics

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
    CFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
    CFrameWnd::Dump(dc);
}

#endif //_DEBUG


// CMainFrame message handlers
------------------------------------------------------------------------------------------------------------------
// Resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by DICOMReaderTest.rc
//
#define IDD_ABOUTBOX                100
#define IDP_OLE_INIT_FAILED            100
#define IDR_MAINFRAME                128
#define IDR_DICOMReaderTestTYPE                129

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE    130
#define _APS_NEXT_CONTROL_VALUE        1000
#define _APS_NEXT_SYMED_VALUE        101
#define _APS_NEXT_COMMAND_VALUE        32771
#endif
#endif
------------------------------------------------------------------------------------------------------------------
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently

#pragma once

#ifndef _SECURE_ATL
#define _SECURE_ATL 1
#endif

#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN            // Exclude rarely-used stuff from 
Windows headers
#endif

#include "targetver.h"

#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString 
constructors will be explicit

// turns off MFC's hiding of some common and often safely ignored 
warning messages
#define _AFX_ALL_WARNINGS

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions


#include <afxdisp.h>        // MFC Automation classes



#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h>           // MFC support for Internet Explorer 4 
Common Controls
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>                     // MFC support for Windows 
Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT


------------------------------------------------------------------------------------------------------------------
// targetver.h
#pragma once

// The following macros define the minimum required platform.  The 
minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has 
the necessary features to run
// your application.  The macros work by enabling all features available 
on platform versions up to and
// including the version specified.

// Modify the following defines if you have to target a platform prior 
to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for 
different platforms.
#ifndef WINVER                          // Specifies that the minimum 
required platform is Windows Vista.
#define WINVER 0x0600           // Change this to the appropriate value 
to target other versions of Windows.
#endif

#ifndef _WIN32_WINNT            // Specifies that the minimum required 
platform is Windows Vista.
#define _WIN32_WINNT 0x0600     // Change this to the appropriate value 
to target other versions of Windows.
#endif

#ifndef _WIN32_WINDOWS          // Specifies that the minimum required 
platform is Windows 98.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to 
target Windows Me or later.
#endif

#ifndef _WIN32_IE                       // Specifies that the minimum 
required platform is Internet Explorer 7.0.
#define _WIN32_IE 0x0700        // Change this to the appropriate value 
to target other versions of IE.
#endif

------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------




More information about the Insight-users mailing list