⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imageviewerview.cpp

📁 图像显示软件源码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/****************************************************************************
ImageViewerView.cpp : Implementation file for the CImageViewerView class
written by PJ Arends
pja@telus.net

For updates check http://www.codeproject.com/tools/imageviewer.asp

-----------------------------------------------------------------------------
This code is provided as is, with no warranty as to it's suitability or usefulness
in any application in which it may be used.

This code may be used in any way you desire. This file may be redistributed by any
means as long as it is not sold for profit, and providing that this notice and the
author's name are included. Any modifications not made by the original author should
be clearly marked as such to remove any confusion between the original version and
any other versions.

If any bugs are found and fixed, a note to the author explaining the problem and
fix would be nice.
-----------------------------------------------------------------------------
****************************************************************************/

#include "stdafx.h"
#include "ImageViewerApp.h"

#include "ImageViewerDoc.h"
#include "ImageViewerView.h"
#include "MainFrm.h"
#include "WindowScroller.h"
#include "SelectImageDialog.h"
#include "DeleteImageDialog.h"
#include "BitmapInfoHeader.h"

#include "..\common files\pja_bitmap.h"
#include "..\common files\pja_dc.h"
#include "..\common files\pja_format.h"

#include <math.h>

//#define ACTIVATE_VIEWER
#include <ImageViewer.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// When the user presses the left mouse button down and
// then moves the mouse cursor to an edge of the view the
// view will scroll. These defines are for that scrolling.
#define AUTOSCROLLTIMERID       0xFEB11965              // Timer ID
#define AUTOSCROLLTIMERSPEED    USER_TIMER_MINIMUM      // Timer and scrolling speed
#define AUTOSCROLLBORDER        4                       // pixels from edge within which scrolling is active

// Mouse gesture IDs
#define GESTUREUP               0x01
#define GESTUREDOWN             0x02
#define GESTURELEFT             0x03
#define GESTURERIGHT            0x04

// CImageViewerView

IMPLEMENT_DYNCREATE(CImageViewerView, CScrollView)

BEGIN_MESSAGE_MAP(CImageViewerView, CScrollView)
    ON_WM_ERASEBKGND()
    ON_WM_HSCROLL()
    ON_WM_KEYDOWN()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_MBUTTONDOWN()
    ON_WM_MOUSEMOVE()
    ON_WM_MOUSEWHEEL()
    ON_WM_SETFOCUS()
    ON_WM_SIZE()
    ON_WM_TIMER()
    ON_WM_VSCROLL()

    ON_MESSAGE(WMU_GETPOINTDATA, &CImageViewerView::OnGetPointData)
    ON_REGISTERED_MESSAGE(WMU_MOUSEGESTURE, &CImageViewerView::OnMouseGesture)

    ON_COMMAND(ID_IMAGE_FIRST, &CImageViewerView::OnImageFirst)
    ON_UPDATE_COMMAND_UI(ID_IMAGE_FIRST, &CImageViewerView::OnUpdateImageFirst)

    ON_COMMAND(ID_IMAGE_PREVIOUS, &CImageViewerView::OnImagePrevious)
    ON_UPDATE_COMMAND_UI(ID_IMAGE_PREVIOUS, &CImageViewerView::OnUpdateImagePrevious)

    ON_COMMAND(ID_IMAGE_SELECT, &CImageViewerView::OnImageSelect)
    ON_UPDATE_COMMAND_UI(ID_IMAGE_SELECT, &CImageViewerView::OnUpdateImageSelect)

    ON_COMMAND(ID_IMAGE_NEXT, &CImageViewerView::OnImageNext)
    ON_UPDATE_COMMAND_UI(ID_IMAGE_NEXT, &CImageViewerView::OnUpdateImageNext)

    ON_COMMAND(ID_IMAGE_LAST, &CImageViewerView::OnImageLast)
    ON_UPDATE_COMMAND_UI(ID_IMAGE_LAST, &CImageViewerView::OnUpdateImageLast)

    ON_COMMAND(ID_ZOOM_ZOOMIN, &CImageViewerView::OnZoomZoomIn)
    ON_UPDATE_COMMAND_UI(ID_ZOOM_ZOOMIN, &CImageViewerView::OnUpdateZoomZoomIn)

    ON_COMMAND(ID_ZOOM_ZOOMOUT, &CImageViewerView::OnZoomZoomOut)
    ON_UPDATE_COMMAND_UI(ID_ZOOM_ZOOMOUT, &CImageViewerView::OnUpdateZoomZoomOut)

    ON_COMMAND(ID_ZOOM_GRID, &CImageViewerView::OnZoomGrid)
    ON_UPDATE_COMMAND_UI(ID_ZOOM_GRID, &CImageViewerView::OnUpdateZoomGrid)

    ON_COMMAND(ID_IMAGE_DELETE, &CImageViewerView::OnImageDelete)
    ON_UPDATE_COMMAND_UI(ID_IMAGE_DELETE, &CImageViewerView::OnUpdateImageDelete)

    ON_COMMAND(ID_VIEW_CENTER_MOUSE, &CImageViewerView::OnViewCenterMouse)
    ON_UPDATE_COMMAND_UI(ID_VIEW_CENTER_MOUSE, &CImageViewerView::OnUpdateViewCenterMouse)

#if !defined NO_GDIPLUS
    ON_COMMAND(ID_IMAGE_SAVE, &CImageViewerView::OnImageSave)
    ON_UPDATE_COMMAND_UI(ID_IMAGE_SAVE, &CImageViewerView::OnUpdateImageSave)
#endif // #if !defined NO_GDIPLUS

END_MESSAGE_MAP()

// supported zoom ratios in percentage. feel free to add or remove from this list.
// As of version 2.3 any zoom ratios over 100% have to be multiples of 100. The new
// drawing code is kind of screwy at other zoom ratios as I have problems synchronizing
// the grid lines and pixel borders.
const LONG ZoomRatios[] = { 1, 5, 10, 25, 50, 75, 100, 200, 300, 400, 500, 700, 1000, 1200, 1500, 2000, 3500, 5000 };

// CImageViewerView construction/destruction

CImageViewerView::CImageViewerView()
: CurrentImage(0xffffffff)  // ensure an invalid value
, CurrentZoomRatio(6)       // 100%
, ViewGrid(false)
, AutoScrollTimer(false)
, LButtonDown(false)
, ZoomedBitmapRect(0, 0, 0, 0)
{
#ifdef _DEBUG
    // check the values in the ZoomRatios array
    // must be >0 and in ascending order
    // any magnification must be a multiple of 100
    size_t CountOfZoomRatios = _countof(ZoomRatios);
    ASSERT(CountOfZoomRatios > 0);
    ASSERT(CurrentZoomRatio >= 0);
    ASSERT(CurrentZoomRatio < CountOfZoomRatios);
    ASSERT(100 == ZoomRatios[CurrentZoomRatio]);

    for (size_t counter = 0; counter < CountOfZoomRatios; ++counter)
    {
        ASSERT(ZoomRatios[counter] > 0);

        if (counter > 0)
        {
            ASSERT(ZoomRatios[counter] > ZoomRatios[counter - 1]);
        }
        
        if (ZoomRatios[counter] > 100)
        {
            ASSERT(0 == ZoomRatios[counter] % 100);
        }
    }
#endif
}

CImageViewerView::~CImageViewerView()
{
}

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

    return CScrollView::PreCreateWindow(cs);
}

// CImageViewerView drawing

void CImageViewerView::OnDraw(CDC* pDC)
{
    CRect ClipBox;
    if (ZoomedBitmapRect.IsRectEmpty())
    {
        GetClientRect(ClipBox);
    }
    else
    {
        pDC->GetClipBox(ClipBox);
    }

    if (ClipBox.IsRectEmpty())
    {
        return;
    }

    // Create a NULL pen and pattern brush for drawing the grid lines
    CPen Pen(PS_NULL, 1, RGB(0, 0, 0));
    CBitmap GridBitmap;
    GridBitmap.LoadBitmap(IDB_GRIDBRUSH);
    CBrush Brush(&GridBitmap);

    // create a double buffer dc and bitmap the size of the clipbox
    // The dc must be created after any GDI objects that are selected into it
    pja::CBitmap DoubleBufferBitmap(*pDC, ClipBox.Width(), ClipBox.Height());
    pja::CCompatibleDC DoubleBufferDC(*pDC);

    // Select the GDI objects into the double buffer DC
    // These are cleaned up automatically in the CCompatibleDC's d'tor
    SelectObject(DoubleBufferDC, DoubleBufferBitmap);
    SelectObject(DoubleBufferDC, Pen);
    SelectObject(DoubleBufferDC, Brush);


    // fill the double buffer dc with the background colour
    COLORREF BackGround = static_cast<COLORREF>(AfxGetMainWnd()->SendMessage(WMU_GETBGCOLOUR, 0, 0));
    CBrush BackgroundBrush(BackGround);
    FillRect(DoubleBufferDC, CRect(0, 0, ClipBox.Width(), ClipBox.Height()), BackgroundBrush);

    if (ZoomedBitmapRect.IsRectEmpty())
    {
        // no bitmap, display error text
        CString ErrorText;
        ErrorText.LoadString(IDS_NOIMAGE);
        BackGround = (GetRValue(BackGround) * 299 + GetGValue(BackGround) * 587 + GetBValue(BackGround) * 114) > 105000 ? RGB(0, 0, 0) : RGB(255, 255, 255);
        SetTextColor(DoubleBufferDC, BackGround);
        SetBkMode(DoubleBufferDC, TRANSPARENT);
        DrawText(DoubleBufferDC, ErrorText, -1, ClipBox, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    }
    else
    {
        bool ShowGrid = ViewGrid && ZoomRatios[CurrentZoomRatio] > 199;
        bool ShowOutline = ViewGrid && ZoomRatios[CurrentZoomRatio] < 200;

        // do the clip box and bitmap area intersect?
        CRect IntersectRect = ZoomedBitmapRect & ClipBox;
        if (!IntersectRect.IsRectEmpty())
        {
            // yes they do, calculate what area of the bitmap needs to be drawn, and where in the clipbox to draw it
            int to_x = ClipBox.left > ZoomedBitmapRect.left ? 0 : ZoomedBitmapRect.left - ClipBox.left;
            int to_y = ClipBox.top > ZoomedBitmapRect.top ? 0 : ZoomedBitmapRect.top - ClipBox.top;

            CRect FromRect(GetPixelFromPoint(IntersectRect.TopLeft()), GetPixelFromPoint(IntersectRect.BottomRight()));
            // so we do not clip the right and bottom sides
            FromRect.InflateRect(0, 0, 1, 1);

            if (ZoomRatios[CurrentZoomRatio] > 100)
            {
                // ensure placement of the left and top pixels
                // TODO: This is where I have problems with zoom ratios that are not
                // multiples of 100. Depending on what the ratio is and which pixel falls
                // on the left side of the clipbox I can not coordinate this clipped area
                // and the grid lines with the StretchBlt() drawing of the original full
                // image. I can end up being out by a single pixel, plus or minus.
                if (0 == to_x)
                {
                    to_x = ZoomedBitmapRect.left - ClipBox.left + FromRect.left * ZoomRatios[CurrentZoomRatio] / 100;
                }

                if (0 == to_y)
                {
                    to_y = ZoomedBitmapRect.top - ClipBox.top + FromRect.top * ZoomRatios[CurrentZoomRatio] / 100;
                }
            }

            int to_w = FromRect.Width() * ZoomRatios[CurrentZoomRatio] / 100;
            int to_h = FromRect.Height() * ZoomRatios[CurrentZoomRatio] / 100;

            pja::CCompatibleDC CurrentBitmapDC;
            SelectObject(CurrentBitmapDC, CurrentBitmap);

            SetStretchBltMode(DoubleBufferDC, ZoomRatios[CurrentZoomRatio] < 100 ? HALFTONE : COLORONCOLOR);

            StretchBlt(DoubleBufferDC,
                       to_x, to_y, to_w, to_h,
                       CurrentBitmapDC,
                       FromRect.left, FromRect.top, FromRect.Width(), FromRect.Height(),
                       SRCCOPY);

            if (ShowGrid)
            {
                // Draw the grid lines
                SetStretchBltMode(DoubleBufferDC, HALFTONE); // see MSDN for SetBrushOrgEx()
                SetBrushOrgEx(DoubleBufferDC, ClipBox.left % 8, ClipBox.top % 8, NULL);

                // vertical
                CRect rc;
                rc.top = IntersectRect.top - ClipBox.top;
                rc.bottom = rc.top + IntersectRect.Height();
                if (IntersectRect.bottom <= ZoomedBitmapRect.bottom)
                {
                    ++rc.bottom;
                }

                for (int x = to_x * 100; x < (to_x + to_w) * 100; x += ZoomRatios[CurrentZoomRatio])
                {
                    rc.left = x / 100 - 1;
                    rc.right = rc.left + 2;
                    Rectangle(DoubleBufferDC, rc.left, rc.top, rc.right, rc.bottom);
                }

                // horizontal
                rc.left = IntersectRect.left - ClipBox.left;
                rc.right = rc.left + IntersectRect.Width();
                if (IntersectRect.right <= ZoomedBitmapRect.right)
                {
                    ++rc.right;
                }

                for (int y = to_y * 100; y < (to_y + to_h) * 100; y += ZoomRatios[CurrentZoomRatio])
                {
                    rc.top = y / 100 - 1;
                    rc.bottom = rc.top + 2;
                    Rectangle(DoubleBufferDC, rc.left, rc.top, rc.right, rc.bottom);
                }
            }
        }

        if (ShowGrid || ShowOutline)
        {
            // draw the outline
            SetStretchBltMode(DoubleBufferDC, HALFTONE); // see MSDN for SetBrushOrgEx()
            SetBrushOrgEx(DoubleBufferDC, ClipBox.left % 8, ClipBox.top % 8, NULL);

            // The outline is drawn around the outside of the image, not over top of it.
            // With the grid the first left and top lines are also drawn outside the image, but
            // the last right and bottom grid lines are drawn on the image.
            CRect OutlineRect(ZoomedBitmapRect);
            OutlineRect.InflateRect(1, 1, 1, 1);
            IntersectRect = OutlineRect & ClipBox;
            if (!IntersectRect.IsRectEmpty())
            {
                CRect rc;
                rc.top = IntersectRect.top - ClipBox.top;
                rc.bottom = rc.top + IntersectRect.Height();
                if (ShowOutline)
                {
                    ++rc.bottom;
                }

                if (ClipBox.left <= ZoomedBitmapRect.left && ClipBox.right >= ZoomedBitmapRect.left)
                {
                    // Draw the left grid line
                    rc.right = ZoomedBitmapRect.left - ClipBox.left + 1;
                    rc.left = rc.right - 2;
                    Rectangle(DoubleBufferDC, rc.left, rc.top, rc.right, rc.bottom);
                }   

                if (ShowOutline && ClipBox.left <= ZoomedBitmapRect.right && ClipBox.right >= ZoomedBitmapRect.right)
                {
                    // Draw the right grid line
                    rc.right = ZoomedBitmapRect.right - ClipBox.left + 2;
                    rc.left = rc.right - 2;
                    Rectangle(DoubleBufferDC, rc.left, rc.top, rc.right, rc.bottom);
                }

                rc.left = IntersectRect.left - ClipBox.left;
                rc.right = rc.left + IntersectRect.Width();
                if (ShowOutline)
                {
                    ++rc.right;
                }

                if (ClipBox.top <= ZoomedBitmapRect.top && ClipBox.bottom >= ZoomedBitmapRect.top)
                {
                    // Draw the top grid line
                    rc.bottom = ZoomedBitmapRect.top - ClipBox.top + 1;
                    rc.top = rc.bottom - 2;
                    Rectangle(DoubleBufferDC, rc.left, rc.top, rc.right, rc.bottom);
                }

                if (ShowOutline && ClipBox.top <= ZoomedBitmapRect.bottom && ClipBox.bottom >= ZoomedBitmapRect.bottom)
                {
                    // Draw the bottom grid line
                    rc.bottom = ZoomedBitmapRect.bottom - ClipBox.top + 2;
                    rc.top = rc.bottom - 2;
                    Rectangle(DoubleBufferDC, rc.left, rc.top, rc.right, rc.bottom);
                }
            }
        }
    }

    //ShowGraphic(DoubleBufferDC);

    // now copy the double buffer dc to the screen
    BitBlt(*pDC,
           ClipBox.left, ClipBox.top, ClipBox.Width(), ClipBox.Height(),
           DoubleBufferDC,
           0, 0,
           SRCCOPY);
}

BOOL CImageViewerView::OnEraseBkgnd(CDC*)
{
    return TRUE;
}

void CImageViewerView::OnInitialUpdate()
{
    SetScrollSizes(MM_TEXT, CSize(0, 0));

    MouseGesture.Attach(*this, 20);
    CMouseGesture::Motion Up[] = {CMouseGesture::RightButton, CMouseGesture::Up};
    CMouseGesture::Motion Down[] = {CMouseGesture::RightButton, CMouseGesture::Down};
    CMouseGesture::Motion Left[] = {CMouseGesture::RightButton, CMouseGesture::Left};
    CMouseGesture::Motion Right[] = {CMouseGesture::RightButton, CMouseGesture::Right};

    MouseGesture.AddGesture(GESTUREUP, Up, _countof(Up));
    MouseGesture.AddGesture(GESTUREDOWN, Down, _countof(Down));
    MouseGesture.AddGesture(GESTURELEFT, Left, _countof(Left));
    MouseGesture.AddGesture(GESTURERIGHT, Right, _countof(Right));

    OnUpdate(NULL, 0xfeb1, NULL);
}


// CImageViewerView diagnostics

#ifdef _DEBUG
void CImageViewerView::AssertValid() const
{
    CScrollView::AssertValid();
}

void CImageViewerView::Dump(CDumpContext& dc) const
{
    CScrollView::Dump(dc);
}

CImageViewerDoc* CImageViewerView::GetDocument() const // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CImageViewerDoc)));
    return (CImageViewerDoc*)m_pDocument;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -